Ich habe jetzt noch ein kleineres Problem. Mein C++ Compiler klopft mir auf die Finger wenn ich zum Beispiel die sprintf Funktion nutzen möchte und als String zum Beispiel den Datentyp uint8_t definiert habe. Kann man das auch irgendwie definieren, dass der Compiler merkt, dass es der gleiche Datentyp ist? Bzw. was benutzt ihr allgemein so für Datentypen wenn ihr in C++ programmiert? Ich wollte gern bei den vorgeschlagenen Datentypen im Tutorial bleiben. Also uint8_t, uint16_t...
Ich denke nicht, dass es sinnvoll ist, ALLE Variablen mit den uint.. Typen zu definieren. Ein String besteht nun mal aus Zeichen, also char (oder wchar etc) und sollte damit definiert werden. Nur für Variablen, bei denen die genaue Größe wichtig ist, und mit denen gerechnet wird (-> deshalb integer), bzw. Bitmanipulationen gemacht werden, sind die uint.. Typen sinnvoll. Also gib Cäsar was des Cäsars ist, und definiere Deine Strings mit char.
Eine Ursache könnte sein, daß print von signed char ausgeht - dann paßt uint8_t natürlich nicht. (C++ unterscheidet da sehr genau.) Versuchs mal mit int8_t. Interessant könnte auch noch sein, wie unint8_t definiert ist. Poste mal die Definition von uint8_t und den Prototyp von sprintf (wie sie im Headerfile deklariert ist), wenn int8_t nicht hilft.
Ich finde das ein wenig inkonsistent. Deshalb bin ich auch Klaus Falser's Meinung diesbezüglich: Klaus Falser wrote: > Ich denke nicht, dass es sinnvoll ist, ALLE Variablen mit den uint.. > Typen zu definieren. > Ein String besteht nun mal aus Zeichen, also char (oder wchar etc) und > sollte damit definiert werden. Datentyp bei Zeichen also: char Datentyp bei (normalen) 8-Bit werten: uint8_t Datentyp bei (normalen) vorzeichenbehafteten 8-Bit werten: int8_t
> Ich finde das ein wenig inkonsistent.
Sehe ich auch so... Nur ist es doch sicherlich lehrreich,
herauszufinden, warum der Compiler meckert, oder?
Uhu Uhuhu wrote: > Sehe ich auch so... Nur ist es doch sicherlich lehrreich, > herauszufinden, warum der Compiler meckert, oder? Weil (per definitionem, auch in C!) "char" != "signed char" != "unsigned char" ist. Auch wenn char stets entweder wie signed char oder wie unsigned char implementiert ist, ist es zu keinem der beiden typkompatibel. Alle drei muss man also einfach klar auseinander halten. Während das in C eine Warnung ist, ist es halt in C++ ein Fehler. Die Umwandlung von char nach uint8_t passiert in der Regel exakt einmal, an der Peripherie. Wenn ich also eine uart_putc()- Funktion für stdio schreibe, so bekommt die ein char rein (weil stdio logischerweise durchweg mit char arbeitet, es sind ja darstellbare Zeichen), und bevor ich dann das char an das USART-Register geben kann, muss ich es halt nach uint8_t casten. Reinzu genau umgekehrt.
Na das hätte doch Lars selber herausfinden sollen... Daß du das weißt, ist nichts neues.
Ist nicht ein char entweder ein signed char oder ein unsigned char? Welcher Fall zutrifft ist implementierungsabhängig, aber jeweils 2 Typen sind meiner Meinung nach identisch.
Identisch sind sie nicht. Wenn du z.B. vergleichen oder gar sortieren willst und Zeichen mit gesetztem oberen Bit hast, spielt das eine sehr große Rolle und C++ packt die Information darüber, um welchen char-Typ es sich handelt, in die Funktionssignatur. Compiler haben üblicherweise eine Defaulteinstellung für den char-Typ. Man kann ihn aber auch per Compileroption einstellen.
Na da habe ich ja eine schöne Diskussion ausgelöst. ;-) Also zunächst hatte ich mich an das Tutorial hier auf der Seite gehalten. Da ist das Beispiel bei: "Die Nutzung von printf" ... uint8_t s[20]; sprintf( s, "Zählerstand: %d", value ); uart_puts( s ); ... Das müsste mit dem C-Compiler funktionieren, mit dem C++ Compiler aber nicht. Ich glaube das Tutorial ist hier an der stelle etwas großzügig, oder? Das signed char und unsigned char nicht das gleiche ist, ist mir schon klar, aber wo ist dann der Unterschied zu char?
Für char nimmt der Compiler entweder den Default-Typ, oder den per Option eingestellten. Was der Default bei gcc ist, weiß ich nicht - da mußt du eben mal nachlesen... Bei VC z.B. ist es unsigned char. C ist bei solchen Kleinigkeiten nicht so pingelig und castet implizit.
> Ist nicht ein char entweder ein signed char oder ein unsigned char? Nein. > Welcher Fall zutrifft ist implementierungsabhängig, aber jeweils 2 > Typen sind meiner Meinung nach identisch. Die interne Wert-Repräsentation ist mit einer von beiden identisch (mit welcher, ist tatäschlich implementierungsabhängig, und beide Varianten sind verbreitet), aber dennoch ist char immer ein eigener Typ. > Was der Default bei gcc ist, weiß ich nicht Das ist wiederum von der Zielplattform abhängig. Bei avr ist es meines Wissens vorzeichenbehaftet. Da man aber für Zeichen (und nur dafür) eh immer char verwendet, spielt das keine Rolle. Wie Jörg schon geschrieben hat, castet man das dort, wo es zur Hardware geht, einmal um. Ob char ein Vorzeichen hat oder nicht, braucht man überhaupt nicht zu wissen.
Mit anderen Worten: eine Applikation, die zum C-Standard konform ist, darf ihr Verhalten nicht ändern, egal ob "char" signed oder unsigned implementiert ist. Bei C ist das eine Warnung, bei C++ ist es ein Fehler, wenn man beides miteinander vermischt.
Das führt aber in eine üble Falle: Angenommen, Modul A ist mit der Option 'char is signed' compiliert und Modul B mit 'char is unsigned' und in beiden Modulen werden Zeichen verglichen. Der Linker merkt nicht, daß die in den Modulen definierten Funktionen von völlig verschiedenen Voraussetzungen ausgehen und nagelt daraus ein Programm zusammen... Das widerspricht der Grundannahme 'Typsicherheit' von C++ eklatant und deckt sich auch nicht mit den täglichen Erfahrungen, die man so mit Linkerproblemen macht. Der Sache mussen wir auf den Grund gehen. Rolf, kannst du deine Ausführungen belegen?
> Angenommen, Modul A ist mit der Option 'char is signed' compiliert und > Modul B mit 'char is unsigned' und in beiden Modulen werden Zeichen > verglichen. Deshalb belässt man das auch auf Default und stellt es nicht per Kommandozeile um. > Das widerspricht der Grundannahme 'Typsicherheit' von C++ eklatant und > deckt sich auch nicht mit den täglichen Erfahrungen, die man so mit > Linkerproblemen macht. Es gibt noch andere Compiler-/Linkeroptionen, die auf das ABI Einfluß haben. Wenn man die anfaßt, ist man eben selbst dafür verantwortlich, daß das Programm und alle verwendeten Bibliotheken mit denselben Einstellungen übersetzt sind bzw. daß man nichts davon übergreifend verwendet. Wenn man ein Programm mit -mint8 (int-Größe auf 8 Bit verstellen) compiliert, ist ja auch klar, daß man das nicht einfach mit anderem Code zusammenlinken kann, bei dem die Option nicht gesetzt ist. > Rolf, kannst du deine Ausführungen belegen? Welche meinst du? Ich habe nicht behauptet, man könne Code, der verschiedene Einstellungen verwendet, beliebig mischen, sondern nur, daß es mir als Programmierer egal sein kann, ob char signed oder unsigned ist. Daß es programmweit einheitlich sein muß, ist eigentlich klar.
In meinem Nachschlagewerk: C/C++ Die Referenz, steht zu Datentypen: unsigned char 0 bis 255 1Byte signed char -128 bis 127 1Byte Das ist ja denke ich mal auch allen klar und verständlich. Und was ist jetzt char? Rolf kannst du uns das bitte nochmal genau erklären, wenn das keiner der beiden sein sollte?
@Lars: Grundsätzlich (default-Einstellung, ANSI-Standard) gilt: Wenn die VOrzeichenangabe bei einem Datentyp weggelassen wird, ist der Typ vorzeichenbehaftet. Der Wertebereich von char entspricht also dem von signed char. Bei einem int gilt entsprechendes. Man kann dem Compiler aber optional mitteilen, dass er den Datentyp (in den mir bekannten Fällen geht das afair aber nur für char) ohne Vorzeichenangabe als unsigned behandeln soll. Das ist dann aber eine lokale, benutzerspezifische Einstellung, die nicht mit dem Standard kompatibel ist. Wenn man char allerdings nur für Textzeichen (ASCII) verwendet (wie es ja auch ursprünglich vorgesehen ist, der Datentyp heißt nicht umsonst "Character"), ist es völlig wurscht, ob man die Einstellung abweichend vom Default gemacht hat, weil die Einstellung ja für alle char im Code gilt. Der "Missbrauch" von char als Rechenvariable ist auch auf 8-Bit-Systemen eigentlich überflüssig, wenn man die stdint.h einbindet und die darin befindlichen Datentypen benutzt (und char eben nur für ASCII-Zeichen verwendet).
@Rolf Magnus Ich habs mit VC2005 mal näher unter die Lupe genommen: char ist dort per Voreinstellung signed char. Die Kommandozeilenoption /J ändert char in unsigned char. Der Compiler erzeugt für char tatsächlich dieselbe Funktionssignatur, gleichgültig, ob mit oder ohne /J compiliert. Die Fehlermeldung, von der Lars berichtet - die er aber nicht gepostet hat - kommt dann wohl davon, daß die gcc Runtimelib kein sprintf für den Typ unsigned char enthält.
Johannes M. wrote: > Wenn man char allerdings nur für Textzeichen (ASCII) verwendet (wie es > ja auch ursprünglich vorgesehen ist, der Datentyp heißt nicht umsonst > "Character"), ist es völlig wurscht, ob man die Einstellung abweichend > vom Default gemacht hat, weil die Einstellung ja für alle char im Code > gilt. Das mag für den englischen Zeichensatz gelten - beim deutschen sind etliche Zeichen mit gesetztem obersten Bit codiert und dann ist es schon nicht mehr 'völlig wurscht', denn das Vergleichsergebnis für < und > ist nicht dasselbe.
@Uhu: Da haste natürlich recht. Und das ist vermutlich auch genau der Grund für die Compiler-Option "[X] char als unsigned behandeln"...
Auf jeden Fall ist es der Grund, warum ich signed char als Standardtyp für char nicht mag.
Johannes M. wrote: > Grundsätzlich (default-Einstellung, ANSI-Standard) gilt: Wenn die > VOrzeichenangabe bei einem Datentyp weggelassen wird, ist der Typ > vorzeichenbehaftet. Bei `int' ja, bei `char' nein. Die Vorzeichenhaftigkeit von `char' ist (leider) von den Standards implementierungsabhängig gelassen worden. Daher gilt die Annahme (für ein portables Programm), dass `char', `signed char' und `unsigned char' drei voneinander verschiedene, nicht zuweisungskompatible Datentypen sind, auch wenn der ersten immer tatsächlich als einer der beiden letzten implementiert ist. Unser Waldvogel schrieb: > Das mag für den englischen Zeichensatz gelten - beim deutschen sind > etliche Zeichen mit gesetztem obersten Bit codiert und dann ist es > schon nicht mehr 'völlig wurscht', denn das Vergleichsergebnis für < > und > ist nicht dasselbe. Egal, der Vergleich auf kleiner oder größer ist vom Standard sowieso nur für die Buchstaben a..z, A..Z und die Ziffern 0..9 jeweils untereinander definiert. Alles andere kann man nicht auf kleiner oder größer vergleichen. Damit ist es auch egal, ob char nun vorzeichenbehaftet ist oder nicht. > daß die gcc Runtimelib kein sprintf für den > Typ unsigned char enthält. Alle stdio-Operationen gemäß Standard arbeiten auf dem Typ `char' und sind damit unverträglich mit sowohl `signed char' als auch `unsigned char'. Mir ist unklar, was es hier immer noch zu diskutieren gibt... Der Standard ist doch so sonnenklar, alle drei sind als verschieden zu behandeln, punkt.
@Lars Lochmann > In meinem Nachschlagewerk: C/C++ Die Referenz, steht zu Datentypen: > unsigned char 0 bis 255 1Byte > signed char -128 bis 127 1Byte > Das ist ja denke ich mal auch allen klar und verständlich. Allerdings nicht ganz allgemeingültig. Die angegebenen Bereiche sind nach C-Norm nur Mindestwerte. Es wären auch größere Wertebereiche erlaubt. In der Praxis ist es aber in den allermeisten Fällen korrekt. > Und was ist jetzt char? Es hat denselben Wertebereich und dieselbe Größe wie eines der beiden, wobei es vom Compiler abhängt, welches gewählt wird. Es ist aber dennoch nicht derselbe Typ. > Rolf kannst du uns das bitte nochmal genau erklären, wenn das keiner > der beiden sein sollte? Anderes Beispiel: Auf AVR ist int und short gleich groß. Sie haben die gleiche Repräsentation und den gleichen Wertebereich. Dennoch sind es zwei verschiedene Typen. Und so sind auch signed char, unsigned char und char drei eigenständige Typen, obwohl char dieselbe Repräsentation hat wie einer der beiden anderen. In C spielt das keine so große Rolle, aber in C++ kann man z.B. Funktionen überladen. Da kannst du eine Funktion für char, signed char und unsigned char überladen, und der Compiler unterscheidet zwischen den dreien abhängig davon, welchen Typ man übergibt. Folgendes Beispiel-Programm wird vom Compiler nicht akzeptiert, weil er nicht weiß, ob er den Wert nun nach signed char oder nach unsigned char konvertieren soll.
1 | void func(unsigned char c) {} |
2 | void func(signed char c) {} |
3 | |
4 | int main() |
5 | {
|
6 | char c = 'x'; |
7 | func(c); |
8 | }
|
Bei den anderen Integertypen ist das nicht so. int und signed int sind ein und derselbe Typ, daher ist folgender Code auch zulässig in C++:
1 | void func(unsigned int i) {} |
2 | void func(signed int i) {} |
3 | |
4 | int main() |
5 | {
|
6 | int i = 42; |
7 | func(i); |
8 | }
|
@Johannes M. > Grundsätzlich (default-Einstellung, ANSI-Standard) gilt: Wenn die > VOrzeichenangabe bei einem Datentyp weggelassen wird, ist der Typ > vorzeichenbehaftet. Ja, für alle außer char. > Der Wertebereich von char entspricht also dem von signed char. Nicht zwangsweise. @Uhu Uhuhu: > beim deutschen sind etliche Zeichen mit gesetztem obersten Bit codiert > und dann ist es schon nicht mehr 'völlig wurscht', denn das > Vergleichsergebnis für < und > ist nicht dasselbe. Es macht dann zwar einen Unterschied, aber im Prinzip sind eh beide Ergebnisse falsch, weil die Umlaute und anderen Zeichen falsch einsortiert werden. Zur Not schreibt man sich eine Funktion oder ein Makro, wo der Vergleich gekapselt ist, und wo intern auf den gewünschten Typ gecastet wrid. Letztendlich vergleiche ich auf Ungleichheit meistens nur ganze Strings (zum Sortieren), und da ist es die Aufgabe von strcmp, sich darum zu kümmern. > Auf jeden Fall ist es der Grund, warum ich signed char als Standardtyp > für char nicht mag. Das Problem ist in dem Fall der Vergleich, nicht der char-Typ. Sobald du statt mit ASCII z.B. mal mit EBCDIC arbeiten mußt, ist das Ergebnis von < und > auch für die englische Sprache unsinnig.
> Alle stdio-Operationen gemäß Standard arbeiten auf dem Typ `char' > und sind damit unverträglich mit sowohl `signed char' als auch > `unsigned char'. Seufz Wenn es doch nur so wäre. Die Funktionen, die mit Strings arbeiten, benutzen [const] char*, aber die, die mit einzelnen Zeichen arbeiten, verwenden zur zusätzlichen Verwirrung int. Beispiel: int putchar(int c); Aber es kommt noch besser: Diese Funktionen (nicht nur die I/O-Funktionen, sondern auch Sachen wie toupper() oder isalpha() - eben alles, was einzelne Zeichen verarbeitet) erwarten vorzeichenlose Werte, auch dann, wenn char vorzeichenbehaftet ist. Man muß streng nach Norm erst nach unsigned char casten! Die korrekte Verwendung von toupper sieht also so aus:
1 | char c = 'x'; |
2 | c = toupper((unsigned char)c); |
Ohne den Cast ist das Verhalten formal undefiniert.
@Jörg Wunsch > Unser Waldvogel schrieb: Der Uhu ein Waldvogel? Na du hast komische Vorstellungen... http://de.wikipedia.org/wiki/Uhu_%28Vogel%29#Lebensraum
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.