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
unsignedcharbuffer1[12];
2
uint32_tulZeit=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.
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
Dein buffer1 ist "unsigned char []", die Funktionen sind vmtl. "char *"
deklariert, char ist standardmäßig signed. Also passt buffer1 nicht
exakt zu den Funktionsdeklarationen.
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
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
chara=67;
2
unsignedcharb=67;
3
intc=67;
4
chard='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!
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.
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
externvoidschar(signedchar*);
2
externvoiduchar(unsignedchar*);
3
externvoidxchar(char*);
4
5
voidcall(char*xp,signedchar*sp,unsignedchar*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?
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!
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?
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)
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
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.
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
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.
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.
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.