C++ & g++ unsigned int in uint8_t?


08.07.2021, 15:41

Die Frage ist wieder ultra dumm. Er krallt sich die letzten 8, dann muss ich gar nicht nach rechts shiften, ich muss überhaupt nicht shiften, passt scho.

Und bei der Ausgabe kommen nur kryptische Zeichen, weils als char interpretiert wird.

4 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Ich glaube, du verstehst grundlegend falsch, dass es zwischen der Repräsentation von Integern in C++ und der Repräsentation auf Hardware-Ebene einen Unterschied gibt.

Im Folgenden nutze ich keine Binär- sondern Hex-Zahlen, weil die Platzsparender sind!

Wenn du ...

uint32_t x = 0x0F;

... schreibst, wird das in C++ so repräsentiert:

0x00'00'00'0F

Auf Hardware-Ebene hängt es von der Bytereihenfolge ab, und kann Big-Endian, Little-Endian oder eine von zwei Middle-Endian-Varianten sein.

Bei modernen Intel-CPUs, die alle Little-Endian nutzen, sähe das dann so aus:

0x0F'00'00'00

Aber DENNOCH wird es von C++ ganz normal wie ...

0x00'00'00'0F

... behandelt!

Merke: Es ist völlig irrelevant, wie Integer im Speicher auf Hardware-Ebene dargestellt werden! Für C++ beginnen die niederwertigsten Bits IMMER rechts und enden mit den höherwertigsten IMMER links!

Wenn du jetzt also ...

uint32_t x = 0x0F;

... schreibst, ist das identisch, als wenn du ...

uint32_t x = 0x00'00'00'0F;

... schreiben würdest.

Und wenn du einfach nur ...

uint8_t y = x;

... schreibst, werden die linkesten 3 Byte weggeworfen, und nur das rechteste Byte beibehalten. Und zwar ist damit die C++ Repräsentation gemeint!

Nochmal: Es ist völlig Wurst, was auf Hardware-Ebene passiert!

uint32_t a = 0x12345678;
uint16_t b = a; // 0x5678
uint8_t c = a; // 0x78

Wenn du shiften würdest, würde das hier passieren:

uint32_t x = 0x12345678;
uint32_t y = x << 24;
// y == 0x78000000

Bei C++ gibt es übrigens zwei verschiedene Casting-Typen, um die C++ Räpresentation und die Hardware-Repräsentation unterscheiden zu können:

uint32_t x = 0x12345678;

auto a = static_cast<uint8_t>(x);
// a == 0x78

auto b = *reinterpret_cast<uint8_t *>(x);
// b = 0x12
// ... oder ...
// b = 0x78

Im letzteren Falle hängt das Ergebnis von der verwendeten CPU ab (Intel oder ARM) und kann sogar auch völlig anders aussehen!

Disclaimer: Ja, ich weiß, dass der reinterpret-Cast in diesem Falle abhängig von der Hardware UB ist!

Fazit: Wenn du in C++ einen Integer mit 0x12345678 initialisierst, dann hat der auch GENAU diesen Wert, mit dem du dann GENAU so arbeiten kannst.

Was intern auf der Hardware passiert, muss dich (fast nie) nicht interessieren!

Woher ich das weiß:Berufserfahrung
stdio  08.07.2021, 23:51

Nachtrag: Ich sehe gerade, dass ich den Adressoperator beim reinterpret_cast übersehen habe.

Korrekt muss das so aussehen:u

uint32_t x = 0x12345678;
auto y = *reinterpret_cast<uint8_t *>(&x);
0
DualStudieren 
Fragesteller
 09.07.2021, 19:36

Soweit war ich noch gar nicht, lese ich mir noch durch, danke =)

0
DualStudieren 
Fragesteller
 09.07.2021, 19:43

Super danke, soweit war ich doch schon, außer die Geschichte mit den casts. Hat mich übel verwirrt, weil ich davor mal bootloader geschrieben habe, bzw. bisschen damit gespielt und Hexzahlen ausgegeben und bla bla bla und dort gabs halt Big und Little Endian :D

=)

0

Ich müsste das auch in der c99-Spezifikation nachlesen, aber an sich müsste sich das, wenn überhaupt, die niederwertigsten Bits schnappen. Vielleicht ist das aber auch undefiniert.

EDIT:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

Seite 55 (bzw. 43);

When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

Sprich der Wert bleibt unverändert, wenn er im range von uint8_t liegt. Wenn nicht, dann werden die höherwertigen Bits quasi abgeschnitten.

DualStudieren 
Fragesteller
 08.07.2021, 15:38

nutze den visual studio compiler, g++ bringt auch nichts besseres.

Bei c99 hänge ich nicht mehr xD

1
DualStudieren 
Fragesteller
 08.07.2021, 15:47
@Destranix

Siehe Ergänzung, der Frage es war mal wieder peinlich was ich hier getan habe.

1
Destranix  08.07.2021, 15:48
@DualStudieren

Muss dir nicht peinlich sein, an sich eine durchaus berechtigte Frage. Gibt anderes Zeug, das nicht definiert ist, wo man es aber erwarten würde.

1

wenn das ein datenstream wäre dann würde es wohl nur die ersten bits geben . aber du streamst ja nicht via bit .

du schneidest 8 bits raus und zwar die ersten 8 bits , also die von rechts . der wert wird ja irgendwo in einem register stehen und dann wird sich halt nur das zu verarbeitente geschnappt . oder hat man nur 8 bit register ?

also 32 bit wert (bei einem 64er system wohl 64 bit) , werden maximal 8 bit interpretiert und das natürlich beginnend bei bit hoch 0

DualStudieren 
Fragesteller
 08.07.2021, 15:43

passt scho, habs rausgefunden, war mal wieder viel zu blöd. Siehe Ergänzung.

0

Also im Endeffekt willst Du doch die 8 bit haben, die "ganz rechts" stehen. Meiner Meinung nach wäre es also doch so, dass wenn Du die Gefahr umgehen willst, dass die vorderen 24 Bit irgendwie komisch interpretiert werden, erstmal 24 bit nach links shiften müsstest, dann wieder 24 bit nach rechts. Damit sind alle bits 0 bis auf die, die Du haben möchtest.

Dann machst Du einfach einen normalen cast - damit schneidest Du doch die überschüssigen 24 Bit einfach ab. Oder verstehe ich was falsch?

Du könntest vermutlich auch einfach ein & 0xFF machen und das casten.

DualStudieren 
Fragesteller
 08.07.2021, 15:47

Jetzt hab ich dich verwirrt und ich hab alle anderen verwirrt. Ich muss überhaupt nicht shiften, der krallt sich die letzten 8 bit von meinen 32 bit uint und damit hab ich genau das, was ich haben will.

War nur mal wieder ultra verwirrt weil bei meiner Ausgabe nichts kam, naja wie auch, der interpretiert uint_t in Teilen als char und dann kommt keine Zahl, sondern ein Zeichen, super. Das wars mal wieder komplett. xD

Trotzdem danke :D

0