Forum: Mikrocontroller und Digitale Elektronik Compiler Warnung 'ultoa' differ in signedness


von Sven (Gast)


Lesenswert?

Hallo,

mein Compiler schmeißt mir folgende Fehlermeldung raus:
"'ultoa' differ in signedness"

Ich konvertierte dabei ein uint32_t für die Ausgabe auf einem LCD:
1
lcd_setcursor(0,3);
2
lcd_string("Zeit: ");  
3
ultoa( ulZeit, buffer1, 10 );
4
lcd_string( buffer1 );

die beiden Variablen sind so definitert:
1
unsigned char buffer1 [12];
2
uint32_t ulZeit = 0;

Bei anklicken der Compiler Warnung lande ich in der ultoa Zeile und 
einmal in der lcd_string Zeile.

Genaue Fehlermeldung:
zeit.c:794: warning: pointer targets in passing argument 2 of 'ultoa' 
differ in signedness
zeit.c:796: warning: pointer targets in passing argument 1 of 
'lcd_string' differ in signedness

Danke.

von (prx) A. K. (prx)


Lesenswert?

char x[]
ist nicht das gleiche wie
unsigned char x[]

Lass also das "unsigned" an buffer1 weg.

von Sven (Gast)


Lesenswert?

Ok, die Warnung ist weg. Aber verstehen tu ich es nicht.
Gibt es in C denn nur char ohne signed und unsigned oder was ist daran 
faul?

von Ingo (Gast)


Lesenswert?

Sven schrieb:
> Gibt es in C denn nur char ohne signed und unsigned oder was ist daran
> faul?

Der Compiler erwartet ein char, kein unsigned char und kein signed char.
Ist in der Funktion so deklariert.


Ingo

von Konrad S. (maybee)


Lesenswert?

Dein buffer1 ist "unsigned char []", die Funktionen sind vmtl. "char *" 
deklariert, char ist standardmäßig signed. Also passt buffer1 nicht 
exakt zu den Funktionsdeklarationen.

von Sven (Gast)


Lesenswert?

Ok, vielen Dank.

von Oliver S. (oliverso)


Lesenswert?

Sven schrieb:
> Ok, die Warnung ist weg. Aber verstehen tu ich es nicht.
> Gibt es in C denn nur char ohne signed und unsigned oder was ist daran
> faul?

Nein, es gibt alle drei Varianten, und die sind für den Compiler alle 
verschieden.

Oliver

von Kaj (Gast)


Lesenswert?

In vielen µC-compilern bzw. IDEs wird eine Variable des Datentyps 'char' 
standardmäßig als 'unsigned char' behandelt so z.B. AVR-Studio. Unter 
AVR-Studio kann man diese Einstellung auch wieder ausschalten.

Es gibt in C KEINE 'Zeichen' (character) so wie sich das hier einige 
denken!
Wenn man mal von oben genanntem Fall absieht gilt folgendes:
Datentyp angaben, ohne weiter Angaben gelten immer als signed!
char = signed char
int = signed int
usw.

char, egal ob signed oder unsigned, bezeichnet einen Datentyp dessen 
Variablen 1Byte groß sind! (char x;  //x ist 1Byte groß!)

Wenn man mit dem Begriff 'char' nicht klar kommt, kann man auch die 
int_8t verwenden, aber auch da verbirgt sich nur ein Datentyp dessen 
Variablen 1Byte groß sind
(int_8t y; //y ist 1Byte groß!)

Ebenso kann man '#define BYTE char' schreiben wenn man mit den 
Begrifflichkeiten nicht klar kommt. (BYTE z; // z ist 1Byte groß!)

Das was einige hier meinen ist immer nur eine andere Interpretation des 
Inhaltes dieser Variablen!

Wenn ich schreibe:
1
char a=67;
2
unsigned char b=67;
3
int c=67;
4
char d='C'

so wird mit
1
printf("a = %c, b = %c, c = %c, d = %c", a, b, c, d);
immer ein großes c ('C') ausgegeben, weil die werte so Interpretiert 
werden sollten, nämlich als ASCII-Werte!

schreibe ich jetzt:
1
printf("a = %i, b = %i, c = %i, d = %i", a, b, c, d);
so wird immer eine 67 ausgegeben!
ebenso kann ich die werte auch als float bzw. double interpretieren.

Es gibt in C KEINE 'Zeichen'! Es ist IMMER eine frage dessen wie man 
einen Wert interpretiert!

char, signed char und unsigned char sind nur 2 Varianten, wo von 2 
gleich sind, abhängig von den Compiler einstellungen!
Und der einzige unterschied zwischen diesen Datentypen liegt in dem 
Wertebereich: -128 bis 127, bzw. 0 bis 255!

von Karl H. (kbuchegg)


Lesenswert?

Kaj schrieb:

> Wenn man mal von oben genanntem Fall absieht gilt folgendes:
> Datentyp angaben, ohne weiter Angaben gelten immer als signed!
> char = signed char
> int = signed int
> usw.


Das gilt bei int aber nicht bei char.

Ob ein char signed oder unsigned ist entscheidet der Compiler und der 
kann bei fast allen Compilern auch noch mit einem Command Line Switch 
vom Gegenteil überzeugt werden.

Am besten fährt man, wenn man in C 3(!) Datentypen unterscheidet und 
auch so benutzt

   char           Für alles was mit Textverarbeitung zu tun hat.
                  Alle String Funktionen arbeiten mit char oder
                  mit char*

   signed char    wenn man einen kleinen Integer zum rechnen mit
                  Vorzeichen benötigt

   unsigned char  wenn man einen kleinen Integer ohne Vorzeichen
                  benötigt.
                  unsigned char ist auch der Datentyp der Wahl
                  wenn es um Arbeiten mit Bytes geht.

anstelle von signed char bzw. unsigned char ist es eine gute Empfehlung, 
stattdessen die Typen int8_t bzw. uint8_t zu benutzen. Die 3 in C 
verfügbaren Datentypen für alles wofür ein int zu groß ist, sind dann
  * char
  * int8_t
  * uint8_t

An deren Einsatzzweck ändert sich aber nichts. Setzt man sie nach diesem 
Muster (Textverarbeitung, kleiner Integer + Vorzeichen, Bytes) ein, hat 
man die wenigsten Probleme.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kaj schrieb:

> In vielen µC-compilern bzw. IDEs wird eine Variable des Datentyps 'char'
> standardmäßig als 'unsigned char' behandelt so z.B. AVR-Studio. Unter
> AVR-Studio kann man diese Einstellung auch wieder ausschalten.

Was aber keinen Einfluss auf die Warnungen hat.

Zum x-ten Mal: Auch damit ist char was anderes als signed char oder 
unsigned char.
1
extern void schar (signed char*);
2
extern void uchar (unsigned char*);
3
extern void xchar (char*);
4
5
void call (char *xp, signed char *sp, unsigned char *up)
6
{
7
    schar (xp);
8
    schar (sp);
9
    schar (up);
10
11
    uchar (xp);
12
    uchar (sp);
13
    uchar (up);
14
15
    xchar (xp);
16
    xchar (sp);
17
    xchar (up);
18
}
1
$ avr-gcc foo.c -fsyntax-only -Wpointer-sign
2
3
foo.c: In function 'call':
4
foo.c:7:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign]
5
foo.c:1:13: note: expected 'signed char *' but argument is of type 'char *'
6
foo.c:9:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign]
7
foo.c:1:13: note: expected 'signed char *' but argument is of type 'unsigned char *'
8
foo.c:11:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign]
9
foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'char *'
10
foo.c:12:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign]
11
foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'signed char *'
12
foo.c:16:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign]
13
foo.c:3:13: note: expected 'char *' but argument is of type 'signed char *'
14
foo.c:17:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign]
15
foo.c:3:13: note: expected 'char *' but argument is of type 'unsigned char *'

Preisfrage: Wo unterscheiden sich die obgen Meldungen von den folgenden?
1
$ avr-gcc foo.c -fsyntax-only -Wpointer-sign -funsigned-char
2
3
foo.c: In function 'call':
4
foo.c:7:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign]
5
foo.c:1:13: note: expected 'signed char *' but argument is of type 'char *'
6
foo.c:9:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign]
7
foo.c:1:13: note: expected 'signed char *' but argument is of type 'unsigned char *'
8
foo.c:11:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign]
9
foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'char *'
10
foo.c:12:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign]
11
foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'signed char *'
12
foo.c:16:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign]
13
foo.c:3:13: note: expected 'char *' but argument is of type 'signed char *'
14
foo.c:17:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign]
15
foo.c:3:13: note: expected 'char *' but argument is of type 'unsigned char *'

von Anfänger (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> anstelle von signed char bzw. unsigned char ist es eine gute Empfehlung,
> stattdessen die Typen int8_t bzw. uint8_t zu benutzen. Die 3 in C
> verfügbaren Datentypen für alles wofür ein int zu groß ist, sind dann
>
>   * char
>   * int8_t
>   * uint8_t

Danke @Karl Heinz für die schöne Erklärung!

von Und immer an die Leser denken! (Gast)


Lesenswert?

In Schmitt,G.; Mikrocomputertechnik mit Controllern der Atmel 
AVR-RISC-Familie (2008); 4. Aufl. Oldenbourg

findet man in Kapitel 3.1.2 eine Tabelle (S. 191) der Datentypen mit 
folgender Einteilung (Ausschnitt):

uint8_t   unsigned char:  vorzeichenlose kleine Zahlen, Zähler, 
Zeichen

int8_t    char  signed char: vorzeichenbehaftete kleine Zahlen

und weiter

unsigned char meldung[] = "\n\rIhre Eingabe -> ";

Demnach werden Strings nicht mit char, wie es Karl Heinz Buchegger 
empfiehlt, sondern unsigned char verwendet. Dies irritiert mich nun. 
Was ist die bessere Empfehlung?

von Karl H. (kbuchegg)


Lesenswert?

Und immer an die Leser denken! schrieb:

> Demnach werden Strings nicht mit char, wie es Karl Heinz Buchegger
> empfiehlt, sondern unsigned char verwendet. Dies irritiert mich nun.
> Was ist die bessere Empfehlung?

Nicht alles was in Büchern steht ist auch korrekt und empfehlenswert.

Frage: welchen Datentyp haben die Argumente in strcpy()?

Das sind char* bzw. const char*

Das ist weder "signed char" noch "unsigned char". Einfach nur plain 
vanilla "char". Und strcpy ist zweifellos eine Funktion, die zur Text- 
respektive Stringverarbeitung gedacht ist.

Arbeite mit dem was du hast, und du hast weniger Probleme. Das es auf 
den unteren Softwareschichten mal zu einem Cast kommen kann, ist 
unvermeidlich, denn irgendwo wird der Übergang von Zeichen auf Byte 
stattfinden (ich denke jetzt zb an LCD Ausgabefunktionen oder UART 
Funktionen, die irgendwann selbstverständlich in einer einzigen Funktion 
münden, die sich um ein Byte kümmert). An dieser Stelle castet man dann 
eben die Dinge zurecht. Aber in den darüberliegenden Softwareschichten 
ist es immer eine gute Idee, wenn man da strikte Trennung mit sich 
selbst vereinbart. Auf der einen Seite der Trennlinie sind Zeichen bzw. 
Strings ("char") auf der anderen Seite steht die Verwendung als "kleiner 
Integer" (int8_t bzw. uint8_t)

von Und immer an die Leser denken! (Gast)


Lesenswert?

Danke! Das das ist hilfreich und ist verstanden.

von Peter D. (peda)


Lesenswert?

Diese Warnungen hat jemand in den AVR-GCC eingebaut, ohne richtig die 
Konsequenzen zu bedenken.

Den Textfunktionen ist es völlig egal, ob char, unsigned char, signed 
char, uint8_t oder int8_t, sie funktionieren mit jedem 8Bit-Format. 
Daher ist die Warnung so überflüssig, wie ein Kropf.

Oftmals hat man aber komplexe Protokolle zu verarbeiten, die Text und 
Binärwerte enthalten. Definiert man nun so einen Puffer als char, damit 
der GCC Ruhe gibt und will daraus einen 16Bit-Binärwert lesen, fällt man 
mächtig auf die Schnauze.
Da char per default signed ist, wird beim Zusammensetzen der 2 Bytes das 
Low-Byte vorzeichenrichtig erweitert und es kommt Müll raus.
Hätte man den Puffer als uint8_t angelegt, würde man zwar mit Warnungen 
bombardiert, aber alles funktioniert richtig.

D.h. diese übermäßige Geschwätzigkeit provoziert Fehler statt sie zu 
vermeiden!


Peter

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:

> Den Textfunktionen ist es völlig egal, ob char, unsigned char, signed
> char, uint8_t oder int8_t, sie funktionieren mit jedem 8Bit-Format.

Bei strcmp ist das nur egal, wenn dich die Sortierreihenfolge nicht 
interessiert.

Aber wenn du einen Schuldigen suchst: DEC hat das verbrochen, als sie 
der PDP-11 eine automatische Vorzeichenerweiterung bei 8-Bit Operationen 
einbauten. Weshalb char oft signed ist. Andernfalls wäre niemand auf 
diese seltsame Idee gekommen und char ware einheitlich unsigned.

von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Bei strcmp ist das nur egal, wenn dich die Sortierreihenfolge nicht
> interessiert.

Stimmt, strcmp müßte bei Umlauten und anderen Zeichen >127 falsche 
Ergebnisse liefern, wenn diese als negativ erweitert werden.
Ein 'ü' (129) ist dann kleiner als ein 'Ü' (154).

Vermutlich ist das nicht weiter schlimm, aber man sieht, das "char" 
provoziert unerwartete Ergebnisse.

A. K. schrieb:
> Aber wenn du einen Schuldigen suchst:

Ich suche eigentlich nur den Schuldigen für diese unsinnige Warnung.


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:

> Diese Warnungen hat jemand in den avr-gcc eingebaut,
> ohne richtig die Konsequenzen zu bedenken.

Die Warnung ist nicht spezifisch für avr-gcc, sie wird dir bei jeder 
GCC-Architektur begegnen falls aktiviert. Wenn sie nicht behagt, braucht 
man sie nicht zu aktivieren bzw. -Wno-pointer-sign ist dein Freund.


Peter Dannegger schrieb:

> Ich suche eigentlich nur den Schuldigen für diese unsinnige Warnung.

Da befragst du hier das falsche Orakel.

Wenn es sich ernsthaft interessiert, recherchierst du in den Quellen, 
ChangeLogs bzw. Maillinglist-Archiven von GCC.

von Konrad S. (maybee)


Lesenswert?

Peter Dannegger schrieb:
> Stimmt, strcmp müßte bei Umlauten und anderen Zeichen >127 falsche
> Ergebnisse liefern, wenn diese als negativ erweitert werden.

Aus "The Standard C Library" [P. J. Plaugher, 1992], Seite 390:
------
7.11.4.2 The strcmp function
Synopsis
  #include <string.h>
  int strcmp(const char *s1, const char *s2);
Description
  The strcmp function compares the string pointed to by s1 to
  the string pointed to by s2.
Returns
  The strcmp function returns an integer greater than, equal to,
  or less than zero, accordingly as the string pointed to by s1 is
  greater than, equal to, or less than the string pointed to by s2.
------

Und die angegebene Implementierung auf Seite 402:
------
/* strcmp function */
#include <string.h>
int (strcmp)(const char *s1, const char *s2)
  {  /* compare unsigned char s1[], s2[] */
    for (; *s1 == *s2; ++s1, ++s2)
      if (*s1 == '\0')
        return (0);
    return ((*(unsigned char *)s1
      < *(unsigned char *)s2) ? -1 : +1);
  }
------

Man war sich also bei der Spezifikation von ANSI-C im Klaren darüben, 
dass Zeichen als "unsigned char" behandelt werden müssen.

Peter Dannegger schrieb:
> Daher ist die Warnung so überflüssig, wie ein Kropf.

Am anderen Ende der Skala hatte ich mal einen Compiler (auf einer Plexus 
P95, SVR2), der keinen Unterschied gemacht hat zwischen Pointer und 
Integer. Warum auch, belegt beides vier Bytes, passt doch! Würg!
War nicht wirklich lustig da nach einem vergessenen Sternchen zu suchen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Konrad S. schrieb:
>
> Aus "The Standard C Library" [P. J. Plaugher, 1992], Seite 390:
>
> Man war sich also bei der Spezifikation von ANSI-C im Klaren darüben,
> dass Zeichen als "unsigned char" behandelt werden müssen.

"Man" ist in diesem Falle wohl "Herr Plaugher".

Vor nicht allzulanger Zeit wurde auf Kundenwunsch die C-Bibliothek des 
Herrn Plaugher samt Support angeschafft — zu einem Preis, der sich recht 
komfortabel in Einheiten des Jahresgehalts eines IT-Mitarbeiters 
ausdrücken lässt.

Bei den Build-Optionen fiel mir auf, daß im GCC-Setup einige Dateien mit 
-O0 übersetzt wurden nebst Kommentar, GCC erzeuge andernfalls falschen 
Code.

Inspektion der Quellen förterte unmittelbar die Verletzung der 
Aliasing-Regeln von C zutage, und per Support-Anfrage wurde eine 
korrigierte Version angefragt.

Die Antwort verwies darauf, daß der Code korrekt sei, dies schon immer 
so war und die Lib schon immer funktioniert habe, und Herr Plaugher 
Mitautor des C-Standards sei und mithin wisse, was korreter Code ist und 
was nicht.

Diese Anwort hat mich zugegebenermassen verunsichert, worauf ich in den 
GCC Mailinglisten nachfragte; funktionsgleichen Code anbei.

Die Antwort war eindeutig.

Nach einer zweiten Supportanfrage mit Verweis auf die Anworten in der ML 
hat der Herr Plaugher seinen Cocktail beiseite gestellt, sich aus seinem 
Strandkorb erhoben, und wiederwilligst ein paar Zeilen C-Code 
zusammengeschustert, für die sich jeder Hobby-Programmierer schämen 
würde.

Soviel zum Herr Plaugher und seiner C-Bibliothek.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.