Hallo Leute. Habe eine Frage zu folgendem Char Array char werte[5] = { 0xff, 0x00, 0x7e, 0x00 0x00 }; Ich dachte immer char wäre signed, d.h. man kann werte von -128 bis 127 oder so ähnlich reinschreiben. hier wird aber der wert 255 reingeschrieben. Wie geht das? Müsste man nicht unsigned char nehmen? Gruß M.H.
Zunächst wird mal 0xFF drinstehen, ob das dann beim auslesen und weiterverarbeiten als -1 oder 255 interprtiert wird ist andere Baustelle.
wenn ich aber 0 reinschreibe, steht dann in der Speicherstelle 0000 0000 oder eben irgendwie sowas: 1000 0000. Weil signed ja die null in der mitte hat. woher weiss der compiler, welche der beiden möglichkeiten er reinschreiben soll, wenn ich schreibe: char c; c = 0; Gruß M.H.
M. H. schrieb: > Weil signed ja die null in der mitte hat. woher weiss der compiler, > welche der beiden möglichkeiten er reinschreiben soll, wenn ich > schreibe: > > > char c; 0 ist 0 egal ob es signed oder unsigned ist. char ist weder signed noch unsigned, es entscheidet sich erst wenn man etwas damit anstellt.
In meinem Tutorial steht: Bits Min Max char, signed char: 8 -128 127 Laut dieser Definition dürfte der wert 255/FF nicht zulässig sein. Oder wird diese "Wertung" erst beim verrechnen vorgenommen? Gruß M.H. Edit: Also wird der Wert 255 beim Verrechnen als 127 gewertet?
M. H. schrieb: > Laut dieser Definition dürfte der wert 255/FF nicht zulässig sein. nein 255 is das gleich wie -127 - da gibt es keinen binären unterschied. (unsigned char)255 = 255 (signed char)255 = -127
M. H. schrieb: > In meinem Tutorial steht: > > Bits Min Max > char, signed char: 8 -128 127 Dein Tutorial ist falsch. Ob char signed oder unsigned ist entscheidet der Compilerbauer. Und oft genug gibt es einen Compilerschalter mit dem man das überschreiben kann. Am besten gewöhnst du dir an, dass du 3(!) unterschiedliche Datentypen hast: unsigned char signed char char char muss logischerweise eines von den beiden anderen sein. Verwenden wirst du char aber nur dann, wenn es keine Rolle spielt ob mit oder ohne Vorzeichen. Also bei reiner Textverarbeitung. Wenn du einen kleinen Integer brauchst dann ist IMMER entweder signed char oder unsigned char der Datentyp der Wahl. Du willst es nicht dem Compilerbauer überlassen, zu entscheiden, wie das sein soll.
Peter II schrieb: > M. H. schrieb: >> Laut dieser Definition dürfte der wert 255/FF nicht zulässig sein. > nein 255 is das gleich wie -127 - da gibt es keinen binären unterschied. Fast. -1 (wenn wir 2-er Komplement zugrunde legen, was wohl der Fall sein wird)
Nein! 0xff = 0b11111111 = 255 (unsigned) oder -1 bei signed char (Zweierkomplement) 0x80 = 0b10000000 = 128 (unsigned) oder -128 (signed char)
Also kann ich ein signed Char von -128 bis 127 benutzen ein unsigned Char von 0 bis 255 und ein char ist einfach ganz normal so wie in assembler auch von 0-255 oder?
M. H. schrieb: > Laut dieser Definition dürfte der wert 255/FF nicht zulässig sein. Der Wert an sich ist egal. Entscheidend ist das Bitmuster, welches im Byte gespeichert ist. Und erst bei der Verwendung entscheidet sich dann, ob dieses Bitmuster als mit oder ohne Vorzeichen aufgefasst wird. Denn dem Bitmuster selber kann man ohne nährere Information (zb der Zusatzinfo, dass die Variable signed oder unsigned ist) nicht ansehen ob das jetzt eine positive Zahl (zb 255) oder eine negative Zahl (-1) sein soll. Beide haben dasselbe Bitmuster. http://www.mikrocontroller.net/articles/AVR-Tutorial:_Arithmetik8#8-Bit_Arithmetik_ohne_Ber.C3.BCcksichtigung_eines_Vorzeichens
M. H. schrieb: > und ein char ist einfach ganz normal so wie in assembler auch von 0-255 Sagen wir lieber 0x00 bis 0xff oder 0b00000000 bis 0b11111111 Denn char ist i.A signed. Muss es aber nicht, ist Compiler und Einstellungsabhängig.
M. H. schrieb: > Also kann ich ein signed Char von -128 bis 127 benutzen Ja > > ein unsigned Char von 0 bis 255 Ja > > und ein char ist einfach ganz normal so wie in assembler auch von 0-255 NEIN Ein char ist weder noch. Lass das char zum rechnen fallen! char benutzt du in Umgebungen wie char Text[] = "Hallo World"; Da ist es wurscht, ob char signed oder unsigned ist. char nimmst du, wenn du es mit Zeichen oder Zeichenketten zu tun hast. Wenn du aber rechnen willst, dann ist char für dich tabu! Dann gibts nur noch signed char oder unsigned char. Alles andere ist: ask for trouble.
Das funktioniert aber auch: signed char c; c = 255; Da steht dann aber 1111 1111 drin! Das ist aber wenn man es als signed auswertet nicht 255!!! Wie ist das möglich?
M. H. schrieb: > signed char c; > > c = 255; > > Da steht dann aber 1111 1111 drin! Ja, was soll denn der arme µC dagegen machen? Da ist ein Byte, das hat 8 Bit und das du c nennst. Da ist die 255, das sind auch 8 Bit. Alle 1 Und du weist das eine dem anderen zu. Was soll er denn tun, ausser die eine Bitrepäsentierung in die 8 Speicherbits zu schreiben? Er kann sich doch nicht wehren! Dem µC ist das doch völlig wurscht was du hinter den Bytes siehst. Wenn du (auf tiefer loghscher Ebene gesehen) einer Bytespeicherzelle einen Wert zuweist, dann macht der das auch. Du als Programmierer bist der Boss. Du musst wissen welche Anweisungen du gibst. Der µC ist nur der Knecht, der Bits durch die Gegend schaufelt. > Das ist aber wenn man es als signed auswertet nicht 255!!! Natürlich nicht. Denn wenn man diese 8 Bit als signed interpretiert, dann ist das eben -1 (und nicht 255, weil 255 nicht darstellbar ist mit 7 Bit und einem Vorzeichenbit)
woher weiss der Compiler, ob das was auf der rechten seite steht, die absoluten bitpositionen repräsentiert oder, ob das ganze erst umgerechnet werden muss: c = -1 // Führt zu 1111 1111 in der speicherzelle c = 255 //Führt auch zu 1111 1111 in der Zelle. Beim ersten wirds nicht direkt übernommen aber beim Zweiten schon. wann macht der was?
Liebe Leute hier, bei euch fehlen die basics: Ein char ist bei diesen Compilern üblicherweise ein Byte. Ein Byte kann 256 Werte enthalten, von 0x00 ... 0xFF. Wird es als "unsigned char" ausgewertet, so geht der Zahlenbereich von 0 (Null) bis 255 (dezimal). Wird es als "signed" ausgewertet, so geht der Zahlenbereich von -128 bis +127, wobei sozusagen die "Null" in der Mitte liegt. 0xFF 0xFE ... 0x81 0x80 0x7F 0x7E ... 0x01 0x00 (hex) ------------------------------------------------------------------ -1 -2 -127 -128 +127 +126 +1 Null (dezimal) "signed" 255 254 129 128 127 127 1 Null (dezimal) "unsigned" So ist das jedenfalls lt. ANSI Ich kenne keine anderen einstellungsabhängigen Varianten.
M. H. schrieb: > woher weiss der Compiler, ob das was auf der rechten seite steht, die > absoluten bitpositionen repräsentiert Ganz einfach: Der Compiler führt über die Datentypen Buch. Auf der rechten Seite er Zuweisung steht ein Ausdruck. Der hat neben einem Wert auch einen Datentyp (so wie in der Physik alles eine Einheit hat). Wenn es dann darum geht, den Wert des Ausdrucks zuzuweisen, sieht sich der Compiler die linke Seite datantyp mässig an, er sieht sich die rechte Seite datentypmässig an und entscheidet anhand der C-Regeln ob es etwas zu tun gibt. Wenn nicht dann schnappt er sich das Bitmuster von der rechten Seite und sorgt dafür, dass genau dieses Bitmuster auf die links spezifizierte Speicherzelle übrtragen wird. Und genau darmu ist es auch so wichtig, dass man die C-Regeln kennt, nach welchen eventuelle Anpassungen oder Umwandlungen vorgenommen werden.
Im konkreten Fall unsigned char c = 255; links ist ein unsigned char, das ist schon mal klar. rechts steht ein int. Also ein signed int. Das passt also erst mal nicht. Also wird aus dem signed int, erst mal ein unsigned int gemacht. Damit sind links und rechts schon mal signed/unsigned gleich. links ist ein 8-Bit Datentyp, rechts einer mit 16 Bit. Also werden die obersten 8 Bit unter den Tisch fallen gelassen und du unteren 8 Bit zugewiesen. signed char c = 255; links steht ein signed char rechts ein signed int signed/unsigned mässig passt das schon mal. links sind 8 Bit, rechts 16. Also werden von der rechten Seite die obersten 8 Bit unter den Tisch fallen gelassen. (Immer mit der Annahme: char hat 8 Bit, int hat 16 Bit)
Alle zahlen über 127 entsprechen den negativen, ich kann aber dann trotzdem positive zahlen wie z.B 255 reinschreiben, die sind dann halt bei der verarbeitung negativ. Die anderen (positiven) Zahlen haben aber bei signed und unsigned die selben bitmuster. ich glaug langsam dämmerts
M. H. schrieb: > Alle zahlen über 127 entsprechen den negativen, ich kann aber dann > trotzdem positive zahlen wie z.B 255 reinschreiben, die sind dann halt > bei der verarbeitung negativ. Die anderen (positiven) Zahlen haben aber > bei signed und unsigned die selben bitmuster. Genau das ist der springende Punkt: Es geht nur um das Bitmuster, welches in der Speicherzelle steht. Nur: bei der Weiterverarbeitung, zb wenn der s/u char wieder auf einen 16 Bit int aufgeblasen werden muss, dann wird im Falle signed eine Erweiterung auf 16 Bit mit Berücksichtigung eines Vorzeichens gemacht und im anderen Fall (unsigned) eben nicht. Bei unsigned sind alle Bits so wie Gott sie schuf, ohne irgendwelche Sonderbehandlungen. Zb. eine Erweiterung von 8 auf 16 Bit bedeutet bei unsigned einfach nur, dass links 8 Stück 0 Bits ergänzt werden, weil man ja führende 0-en immer links anhängen darf soviel man will, ohne dass sich der Zahlenwert ändert. Das Bitmuster ist immer gleich. Aber die weitere Behandlung unterscheidet sich, je nachdem ob du die Variable signed oder unsigned definiert hast.
malzeit wem die char int, ... zu kompliziert ist und nicht weis ob das ding nun 8 oder 16 oder doch 32 bit hat, sollte lieber gleich uint8_t verwenden. damit ist sollte klar sein das es ein Unsigned int mit 8 bit ist. feierabend. char definiert ein zeichen, ist platform/Programiermodell abhängig, kann 8 als auch 16 bit sein. Es soll Maschienen geben, die können nicht mit 8 bit rechnen / war damals nicht vorgesehen. ein int kann je nach Platform/Programmiermodell 16 32 oder 64 bit sein.
Erich schrieb: > Liebe Leute hier, > bei euch fehlen die basics: > > Ein char ist bei diesen Compilern üblicherweise ein Byte. > Ein Byte kann 256 Werte enthalten, von 0x00 ... 0xFF. > > Wird es als "unsigned char" ausgewertet, so geht der Zahlenbereich > von 0 (Null) bis 255 (dezimal). > > Wird es als "signed" ausgewertet, so geht der Zahlenbereich > von -128 bis +127, wobei sozusagen die "Null" in der Mitte liegt. > > > 0xFF 0xFE ... 0x81 0x80 0x7F 0x7E ... 0x01 0x00 (hex) > ------------------------------------------------------------------ > -1 -2 -127 -128 +127 +126 +1 Null (dezimal) > "signed" > > 255 254 129 128 127 127 1 Null (dezimal) > "unsigned" > > So ist das jedenfalls lt. ANSI Und das alles kannst du auch mit Zitaten aus den entsprechenden ANSI Dokumenten belegen. Wo steht denn eigentlich, dass ein char (egal ob signed oder unsigned) 8 Bit haben muss? Wo steht in den ANSI Dokumenten, dass mit 2-er Komplement gearbeitet werden muss? (Brauchst nicht nachsehen. Es steht nirgends. Ganz im Gegenteil, das wird explizit offen gelassen. Bei den Bitbreiten gibt es gewisse Mindestanforderungen, aber 2-er Komplement wird zb nirgends gefordert. Alte IBM Maschinen hatten eine ganz andere Repräsentierung des Vorzeichens) > Ich kenne keine anderen einstellungsabhängigen Varianten. Dann kennst du offenbar nicht viele.
XYZ schrieb: > ein int kann je nach Platform/Programmiermodell 16 32 oder 64 bit sein. neugier: wo ist denn ein int 64bit?
Malzeit, kommt auf das verwendete Programmiermodell an. hat etwas mit der entwicklung der Maschienen zu tun und der code compatibilität. Ein pointer wurde früher teilweise als unsigned int definiert. auf 32bit war der 32bit gross. wird das nun für 64bit übersetzt und bleibt int 32bit dann past der pointer nicht mehr rein und du hast den salat. der pointer zeigt ggf ganz wo anders hin. http://www.unix.org/version2/whatsnew/lp64_wp.html und zum zweier komplement. es ist nun mal die einfachste variante damit zu rechnen. - du brauchst kein explizietes subtraktions werk, sondern kanst subtraktionen mit dem additionswerk durchführen. - der untere zahlenbeich ist immer gleich egal ob signed oder unsigned. - es kommen keine doppelten zahlen vor / der ganze zahlenraum wird ausgeschöpft. (z.B. einerkomplement mit der positiven / negativen 0) und zu standard. dem ist es föllig egal, da das HW abhängig ist. und die machen das so wie es ihnen gefällt. wenn IBM meint ne bessere möglichkeit gefunden zu haben, dann ist dem so. ändert aber nichts an dem C programm. gruss
Kern der Sache: Hexadezimalwerte werden in der Informatik fast immer vorzeichenlos genutzt, um damit Bitfolgen und nicht etwa numerische Größen abzubilden. ... Hat jemand ein Beispiel für einen Compiler bei dem char tatsächlich unsigned ist? ... Dass Pointer und Ints immer "type punnable" sind halte ich für einen gefährlichen Trugschluss, der wohl aus Notwendigkeit entstanden ist weil man sich nie auf eine Syntax ala Turbo-Pascal "ABSOLUTE" für C geeinigt hat und sich damit das casten von Ints als Standardlösung durchgesetzt hat. Und auch Pointer zu Pointer casten wird nicht immer gut gehen - siehe far/near in Real Mode x86 (unterschiedliche Größen des Pointers selbst!), siehe idata/xdata auf dem 8051 (unterschiedliche Addressräume!), siehe diverse RISC/DSP-Architekturen bei denen wg Alignment bestimmte Addressen für bestimmte Wortlängen schlichtweg unzulässig sind... ...Wer mal 16-Bit C-Code bei denen short und int austauschbar genutzt wurden auf ein 32-Bit System portiert hat ist auch vorsichtig geworden was Annahmen über Datentypen angeht.
Compiler, die per default char unsigned sehen? gcc. Zum Beispiel für ARM. Und daß man ints in Pointer auf Daten casten kann, ist sehr wohl garantiert.
@Martin wie willst Du zB in besagter 16-Bit Umgebung garantieren dass ein 16-Bit(!) Integer einen gültigen far-Pointer ergibt? Das mit dem gcc ARM ist in der Tat interessant - warum, ist das nativ so auf dem ARM?
Andy D. schrieb: > Kern der Sache: Hexadezimalwerte werden in der Informatik fast immer > vorzeichenlos genutzt, um damit Bitfolgen und nicht etwa numerische > Größen abzubilden. richitg. Drumm ist der Datentyp für 0xFF zb auch unsigned int. Der für 255 ist aber signed int. > Und auch Pointer zu Pointer casten wird nicht immer gut gehen - siehe > far/near Im C-Standard gibt es kein near und far. Du schmeisst schon wieder Standard-C und eine spezielle C-Implementierung durcheinander.
Andy D. schrieb: > @Martin wie willst Du zB in besagter 16-Bit Umgebung garantieren dass > ein 16-Bit(!) Integer einen gültigen far-Pointer ergibt? Uninteressant, da es in C keinen far Pointer gibt. Wenn ein Hersteller so etwas einbaut, dann legt er die Regeln fest wie das geschieht. Lass uns aber in erster Linie daran halten, was der C-Standard vorgibt. Wenn ein Neuling diesen Umfang beherrscht UND dann noch weiß wann und aus welchem Grund sein spezielles System dafür eine Sonderregelung getroffen hat, dann ist schon etwas erreicht.
XYZ schrieb: > malzeit Was sollen wir denn malen? > wem die char int, ... zu kompliziert ist und nicht weis ob das ding nun > 8 oder 16 oder doch 32 bit hat, sollte lieber gleich uint8_t verwenden. > damit ist sollte klar sein das es ein Unsigned int mit 8 bit ist. > feierabend. Außer bei Lowlevel-I/O braucht man aber eigentlich nie einen Integer, der zwingend exakt 8 Bit breit sein muß. > char definiert ein zeichen, ist platform/Programiermodell abhängig, kann > 8 als auch 16 bit sein. Aber er ist der kleinstmögliche Datentyp. Auf einem Compiler, wo char 16 Bit breit ist, gibt es kein uint8_t. Und gerade dann ist es ein Vorteil, wenn man nicht überall die Breite unnötigerweise auf exakt 8 Bit gezwungen hat. > Es soll Maschienen geben, die können nicht mit 8 bit rechnen / war damals > nicht vorgesehen. ARM kann auch nicht mit 8 Bit rechnen, aber er kann 8-Bit-Speicheroperationen durchführen, und das ist eher wesentlich. > ein int kann je nach Platform/Programmiermodell 16 32 oder 64 bit sein. oder alles andere, was nicht kleiner als 16 ist. XYZ schrieb: > und zum zweier komplement. es ist nun mal die einfachste variante damit > zu rechnen. Deshalb ist es auch heute das meistverwendete System für vorzeichenbehaftete Rechnung, aber trotzdem nicht das einzige, das es in Prozessoren gibt und auch nicht das einzige, das in C erlaubt ist. > - der untere zahlenbeich ist immer gleich egal ob signed oder unsigned. Das ist in C auch vorgeschrieben. > - es kommen keine doppelten zahlen vor / der ganze zahlenraum wird > ausgeschöpft. (z.B. einerkomplement mit der positiven / negativen 0) Es gibt Berechnungen, die eine Unterscheidung der positiven und negativen 0 brauchen. Deshalb gibt's die bei Floating Point auch. Martin schrieb: > Und daß man ints in Pointer auf Daten casten kann, ist sehr wohl > garantiert. Daß man das kann, ist garantiert, aber nicht garantiert ist die Art der Zuordnung, also also aus welchem int-Wert welche Adresse wird. Außerdem ist nicht garantiert, daß man damit jeden möglichen Zeigerwert erzeugen kann und daß man verlustlos einen Zeiger in einen int und wieder zurück casten kann. Dafür gibt's intptr_t.
@kbuchegg das glaube ich erst wenn mir jemand die entsprechende Stelle im Standard nennt. Wie soll das bitte erst auf 64-Bit Systemen funktionieren, ausser in Implementationen auf denen int gleich long long ist?
@Martin OK, hab ich mich falsch ausgedrückt. Mit "kann man casten" meinte ich "mit definiertem und sicherem Effekt", nicht "mit einem cast kann man ein type punning erzwingen das dazu noch semantisch fehlschlagen wird".
Andy D. schrieb: > @kbuchegg das glaube ich erst wenn mir jemand die entsprechende Stelle > im Standard nennt. Wie soll das bitte erst auf 64-Bit Systemen > funktionieren, ausser in Implementationen auf denen int gleich long long > ist? Welche Aussage glaubst du nicht? Ich verlier gerade den Überblick.
Andy D. schrieb: > ... Hat jemand ein Beispiel für einen Compiler bei dem char tatsächlich > unsigned ist? gcc/PowerPC
Andy D. schrieb: > @kbuchegg das glaube ich erst wenn mir jemand die entsprechende Stelle > im Standard nennt. Was glaubst du nicht? Das es in Standard-C keine far Pointer gibt? Nimm dir den C-Standard, such nach "far" und sieh nach, ob an der Fundstelle von Pointern die Rede ist. > Wie soll das bitte erst auf 64-Bit Systemen > funktionieren, Wie soll was auf 64-Bit Systemen funktionieren? > Wie soll das bitte erst auf 64-Bit Systemen > funktionieren Der C-Standard kennt auch keine 64-Bit Systeme. ALs Grundregel kannst du immer davon ausgehen: Sobald irgendetwas in irgend einer Weise hardwareabhängig oder sonst irgendwie systemspezifisch ist, verliert der C-Standard kein Wort darüber. Der C-Standard kennt keine Monitore oder Tastaturen. Er kennt keine Diskettem oder CD oder USB-Sticks oder Festplatten. Er kennt keine definitiven Bitbreiten und auch keine Charater-Codierungen (ASCII). Er lässt es der Hardware frei, wie sie negative von positiven Zahlen unterscheidet oder wie sie damit rechnet. Der C-Standard legt fest welches sichtbare Verhalten C-Konstrukte erzeugen müssen, aber er sagt nichts darüber aus wie dieses Verhalten konkret zu erzielen ist. Für Datentypen gibt es diverse Mindestanforderungen, das wars dann aber auch schon.
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.