Datum:
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:
lcd_setcursor(0,3); lcd_string("Zeit: "); ultoa( ulZeit, buffer1, 10 ); lcd_string( buffer1 ); |
die beiden Variablen sind so definitert:
unsigned char buffer1 [12]; 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.
Datum:
char x[] ist nicht das gleiche wie unsigned char x[] Lass also das "unsigned" an buffer1 weg.
Datum:
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?
Datum:
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
Datum:
Dein buffer1 ist "unsigned char []", die Funktionen sind vmtl. "char *" deklariert, char ist standardmäßig signed. Also passt buffer1 nicht exakt zu den Funktionsdeklarationen.
Datum:
Ok, vielen Dank.
Datum:
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
Datum:
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:
char a=67; unsigned char b=67; int c=67; char d='C' |
so wird mit
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:
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!
Datum:
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.
Datum:
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.
extern void schar (signed char*); extern void uchar (unsigned char*); extern void xchar (char*); void call (char *xp, signed char *sp, unsigned char *up) { schar (xp); schar (sp); schar (up); uchar (xp); uchar (sp); uchar (up); xchar (xp); xchar (sp); xchar (up); } |
$ avr-gcc foo.c -fsyntax-only -Wpointer-sign foo.c: In function 'call': foo.c:7:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign] foo.c:1:13: note: expected 'signed char *' but argument is of type 'char *' foo.c:9:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign] foo.c:1:13: note: expected 'signed char *' but argument is of type 'unsigned char *' foo.c:11:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign] foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'char *' foo.c:12:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign] foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'signed char *' foo.c:16:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign] foo.c:3:13: note: expected 'char *' but argument is of type 'signed char *' foo.c:17:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign] foo.c:3:13: note: expected 'char *' but argument is of type 'unsigned char *' |
Preisfrage: Wo unterscheiden sich die obgen Meldungen von den folgenden?
$ avr-gcc foo.c -fsyntax-only -Wpointer-sign -funsigned-char foo.c: In function 'call': foo.c:7:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign] foo.c:1:13: note: expected 'signed char *' but argument is of type 'char *' foo.c:9:5: warning: pointer targets in passing argument 1 of 'schar' differ in signedness [-Wpointer-sign] foo.c:1:13: note: expected 'signed char *' but argument is of type 'unsigned char *' foo.c:11:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign] foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'char *' foo.c:12:5: warning: pointer targets in passing argument 1 of 'uchar' differ in signedness [-Wpointer-sign] foo.c:2:13: note: expected 'unsigned char *' but argument is of type 'signed char *' foo.c:16:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign] foo.c:3:13: note: expected 'char *' but argument is of type 'signed char *' foo.c:17:5: warning: pointer targets in passing argument 1 of 'xchar' differ in signedness [-Wpointer-sign] foo.c:3:13: note: expected 'char *' but argument is of type 'unsigned char *' |
Datum:
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!
Datum:
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?
Datum:
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)
Datum:
Danke! Das das ist hilfreich und ist verstanden.
Datum:
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
Datum:
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.
Datum:
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
Datum:
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.
Datum:
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.
Datum:
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.