Forum: Mikrocontroller und Digitale Elektronik GCC: konvertieren von uint64_t in Byte Array


von Peter (Gast)


Lesenswert?

Hallo,

das Bit-Shiften funktioniert nicht. Die oberen 32 Bit sind immer 0.

uint64_t ullValue = 0xFFFFFFFF;
uint8_t ucValue = (uint8_t)((uint64_t)(ullValue >> 40));

Ergebnis: ucValue = 0

Wie kann ich auf die oberen 32 Bit zugreifen ?

Gruß Peter

von Oliver S. (oliverso)


Lesenswert?

Peter schrieb:
> Hallo,
>
> das Bit-Shiften funktioniert nicht.

Doch, tut es.

Peter schrieb:
> 32
> …
> ullValue >> 40

Denk da nochmal kurz drüber nach.

> Ergebnis: ucValue = 0

Das ist richtig.

Oliver

: Bearbeitet durch User
von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Peter schrieb:
> Hallo,
>
> das Bit-Shiften funktioniert nicht. Die oberen 32 Bit sind immer 0.
>
> uint64_t ullValue = 0xFFFFFFFF;
> uint8_t ucValue = (uint8_t)((uint64_t)(ullValue >> 40));
>
> Ergebnis: ucValue = 0
>
> Wie kann ich auf die oberen 32 Bit zugreifen ?
>
> Gruß Peter

Ist ja auch richtig, wenn man den uint64_t nur zur Hälfte befüllt.
Versuchs mal mit 0xFFFFFFFFFFFFFFFF...

Ach, was solls:
1
uint64_t ullValue = 0xFFFFFFFFFFFFFFFF;
2
uint8_t byteArray[8];
3
    
4
for (int i = 0; i < 8; i++)
5
{
6
    byteArray[i] = (uint8_t)(ullValue >> (8 * i));
7
    printf("%d. 0x%x\n", i + 1, byteArray[i]);
8
}

: Bearbeitet durch User
von Peter (Gast)


Lesenswert?

Oliver S. schrieb:
> Denk da nochmal kurz drüber nach.

Tim T. schrieb:
> Ist ja auch richtig, wenn man den uint64_t nur zur Hälfte befüllt.

OMG! - Ich stelle fest: 8 x F != 8 Bytes !!!!

Ich mach da schon ne Stunde rum :)

DANKE an Euch.

Gruß Peter

von Peter D. (peda)


Lesenswert?

Tim T. schrieb:
> uint64_t ullValue = 0xFFFFFFFFFFFFFFFF;

Man kann auch einfacher schreiben:
1
uint64_t ullValue = -1;
Als Zuweisung sind signed Werte erlaubt. Sie werden dann in den 
entsprechenden Binärwert konvertiert.

von Simon (Gast)


Lesenswert?

Gibt es nicht auch:
1
UINT64_MAX

von Oliver S. (oliverso)


Lesenswert?

Das wurde erst nach Peters C-Sozialisierung erfunden...

Oliver

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?


von Simon (Gast)


Lesenswert?

Oliver S. schrieb:
> Das wurde erst nach Peters C-Sozialisierung erfunden...

wobei, wenn ich alle Bits gesetzt haben möchte, würde ich wahrscheinlich 
statt
1
UINT64_MAX
lieber
1
 ~0
schreiben.

von Walter T. (nicolas)


Lesenswert?

Böse Falle. Wenn schon, dann ~0ULL.

Ansonsten kann auf Systemen, bei denen ein Integer nicht 64 Bit breit 
ist, einen kleinerer Wert hinterlegt werden.

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

Walter T. schrieb:
> Ich weiß
> gerade nur nicht, warum. Zumindest bei der Erzeugnung eines
> 32-Bit-Binaries auf einem 64-Bit-System.

Weil der Compiler "annimmt", dass es sich bei "0" um eine Zahl aus dem 
Zielzahlenbereich "uint64_t" handelt?!

Peter D. schrieb:
> Man kann auch einfacher schreiben:uint64_t ullValue = -1;
> Als Zuweisung sind signed Werte erlaubt. Sie werden dann in den
> entsprechenden Binärwert konvertiert.

Da würde ich vermuten, dass ein Warning erzeugt wird (zumindest meckert 
"mein" Keil rum: "warning:  #68-D: integer conversion resulted in a 
change of sign"). Ein Cast sollte reichen.

von Walter T. (nicolas)


Lesenswert?

Ich habe meinen vorheriges Edit gelöscht, weil mein vorheriger Einwand 
gegenstandslos geworden war. Deswegen passt das Zitat nicht mehr zu 
meinem Beitrag.

Sinngemäß stand da: "Nanu, uint64_t a = ~0; funktiert ja."

STK500-Besitzer schrieb:
> Weil der Compiler "annimmt", dass es sich bei "0" um eine Zahl aus dem
> Zielzahlenbereich "uint64_t" handelt?!

Nein, es liegt daran, dass mein Build-Prozeß eine 64-Bit-EXE erzeugt 
hat. Ich hatte es nur vergessen, dass ich vor längerer Zeit umgestellt 
habe.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Wenn schon, dann ~0ULL.

Aber ist uint64_t denn immer unsigned long long?

Da doch lieber
1
UINT64_MAX
 (in C) oder
1
std::numeric_limits<std::uint64_t>::max()
 (C++).

Es ginge auch noch
1
((uint64_t) ~((uint64_t) 0))
 in C bzw.
1
static_cast<std::uint64_t> (~std::uint64_t { 0 })
 in C++, aber schön ist anders. Der äußere Cast ist eventuell je nach 
Plattform nötig um Integer Promotion zu umgehen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Walter T. schrieb:
in, es liegt daran, dass mein Build-Prozeß eine 64-Bit-EXE erzeugt
> hat. Ich hatte es nur vergessen, dass ich vor längerer Zeit umgestellt
> habe.

Nein.
Das Literal 0 hat den Typ int, ~0 invertiert die Bits des int, das 
Ergebnis ist wieder der Typ int (Promotionsregeln) und hat den Wert -1. 
Mit -1 wird dann der uint64_t initialisiert, und dabei wird auf uint64_t 
konvertiert.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Wie praktisch. Das heißt es funktioniert bei allen Bitbreiten, nur aus 
unterschiedlichen Gründen. Kein Wunder, dass man auf Dauer paranoid 
wird.

: Bearbeitet durch User
von Udo K. (udok)


Lesenswert?

Walter T. schrieb:
> Wie praktisch. Das heißt es funktioniert bei allen Bitbreiten, nur aus
> unterschiedlichen Gründen. Kein Wunder, dass man auf Dauer paranoid
> wird.

Nein. Streng genommen ist es UB.  Integer müssen nicht im 2-er 
Kompliment gespeichert werden...

von Wilhelm M. (wimalopaan)


Lesenswert?

Udo K. schrieb:
> Walter T. schrieb:
>> Wie praktisch. Das heißt es funktioniert bei allen Bitbreiten, nur aus
>> unterschiedlichen Gründen. Kein Wunder, dass man auf Dauer paranoid
>> wird.
>
> Nein. Streng genommen ist es UB.  Integer müssen nicht im 2-er
> Kompliment gespeichert werden...

Seit C23 ist 2'er-Komplement verpflichtend.

von jojo (Gast)


Lesenswert?

Ich würde mit einer dieser beiden Lösungen arbeiten. Letztere ist 
vermutlich noch eindeutiger, während man bei der ersten beim Ändern der 
Datentypbreite die Zuweisung nicht ändern muss. Beim zweiten schreit in 
dem Fall aber hoffentlich irgendein Linter oder compiler ;)

Peter D. schrieb:
> uint64_t ullValue = -1;

Simon schrieb:
> UINT64_MAX

von Udo K. (udok)


Lesenswert?

Wilhelm M. schrieb:
> Seit C23 ist 2'er-Komplement verpflichtend.

Das nützt dir nur heute nichts.

von Wilhelm M. (wimalopaan)


Lesenswert?

Udo K. schrieb:
> Wilhelm M. schrieb:
>> Seit C23 ist 2'er-Komplement verpflichtend.
>
> Das nützt dir nur heute nichts.

Doch (bei gcc): -std=c2x

Zitat cppreference:

Prior to C23, the C Standard allowed any signed integer representation, 
and the minimum guaranteed range of N-bit signed integers was from
 (e.g. -127 to 127 for a signed 8-bit type), which corresponds to the 
limits of one's complement or sign-and-magnitude.

However, all popular data models (including all of ILP32, LP32, LP64, 
LLP64) and almost all C compilers use two's complement representation 
(the only known exceptions are some compliers for UNISYS), and as of 
C23, it is the only representation allowed by the standard, with the 
guaranteed range from
 (e.g. -128 to 127 for a signed 8-bit type).

Mit einem UB, was in der Tat heute(!) nicht auftritt, kann ich gut 
leben.

von Veit D. (devil-elec)


Lesenswert?

Wilhelm M. schrieb:
> Udo K. schrieb:
>> Nein. Streng genommen ist es UB.  Integer müssen nicht im 2-er
>> Kompliment gespeichert werden...
>
> Seit C23 ist 2'er-Komplement verpflichtend.

Hallo,

heißt das in Zukunft darf man auf signed Überläufen vertrauen wie man 
unsigned Überläufen vertrauen darf?

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Wilhelm M. schrieb:
>> Udo K. schrieb:
>>> Nein. Streng genommen ist es UB.  Integer müssen nicht im 2-er
>>> Kompliment gespeichert werden...
>>
>> Seit C23 ist 2'er-Komplement verpflichtend.
>
> Hallo,
>
> heißt das in Zukunft darf man auf signed Überläufen vertrauen wie man
> unsigned Überläufen vertrauen darf?

Nein, das bleibt UB.

von Udo K. (udok)


Lesenswert?

Wilhelm M. schrieb:
>> heißt das in Zukunft darf man auf signed Überläufen vertrauen wie man
>> unsigned Überläufen vertrauen darf?
>
> Nein, das bleibt UB.

Hast du da eine Referenz?  Was wäre sonst der Sinn dahinter?

von Udo K. (udok)


Lesenswert?

Wilhelm M. schrieb:
>> Das nützt dir nur heute nichts.
>
> Doch (bei gcc): -std=c2x

Die gcc Homepage meint dazu:
  A further version of the C standard, known as C2X, is under 
development;
  experimental and incomplete support for this is enabled with -std=c2x.

Aber ich kenne keine aktuelle CPU, die nicht 2-er Kompliment hat, von 
daher ist die Diskussion sinnlos...

von Wilhelm M. (wimalopaan)


Lesenswert?

Udo K. schrieb:
> Aber ich kenne keine aktuelle CPU, die nicht 2-er Kompliment hat, von
> daher ist die Diskussion sinnlos...

Sag ich doch!

von Wilhelm M. (wimalopaan)


Lesenswert?

Udo K. schrieb:
> Wilhelm M. schrieb:
>>> heißt das in Zukunft darf man auf signed Überläufen vertrauen wie man
>>> unsigned Überläufen vertrauen darf?
>>
>> Nein, das bleibt UB.
>
> Hast du da eine Referenz?  Was wäre sonst der Sinn dahinter?

https://en.cppreference.com/w/c/language/operator_arithmetic#Overflows

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Schade das es nicht konsequent umgesetzt wird. Das würde viele Probleme 
beheben. Darf ich fragen was ein Trap ist?
> ... representation (typically 2's complement), it may trap on some
> platforms or due to compiler options (e.g. -ftrapv in GCC and Clang) ...

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> Schade das es nicht konsequent umgesetzt wird. Das würde viele Probleme
> beheben. Darf ich fragen was ein Trap ist?
>> ... representation (typically 2's complement), it may trap on some
>> platforms or due to compiler options (e.g. -ftrapv in GCC and Clang) ...

Ein trap ist ein Software-Interrupt, was das genau bedeutet, ist dann 
eben sehr plattformspezifisch. Auf x86/*nix wird dem Prozess ein SIGABRT 
gesendet.

von Veit D. (devil-elec)


Lesenswert?

Danke.

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
Noch kein Account? Hier anmelden.