Wie kombiniert man zwei 32-Bit-Ganzzahlen zu einer 64-Bit-Ganzzahl?
Lesezeit: 2 Minuten
bei
Ich habe ein Zählregister, das aus zwei 32-Bit-Ganzzahlen ohne Vorzeichen besteht, eine für die höheren 32 Bits des Werts (höchstwertiges Wort) und eine andere für die niedrigeren 32 Bits des Werts (niederwertiges Wort).
Was ist der beste Weg in C, um diese beiden 32-Bit-Ganzzahlen ohne Vorzeichen zu kombinieren und dann als große Zahl anzuzeigen?
Wenn die Zahl auf 4294967296 erhöht wird, habe ich es so, dass das leastSignificantWord auf 0 löscht und das mostSignificantWord (anfänglich 0) jetzt 1 ist. Der gesamte Zähler sollte jetzt 4294967296 anzeigen, aber im Moment zeigt er nur 10 an, weil ich nur verkette 1 von mostSignificantWord und 0 von leastSignificantWord.
Wie soll ich 4294967296 anstelle von 10 anzeigen lassen?
Ihre Methode würde nur Sinn machen, wenn Sie %8.8X als Formatbezeichner verwenden, um die Hexadezimalwerte der Wörter zu verketten. Damit es dezimal funktioniert, müsste der maximale ganzzahlige Wert (10^n)-1 sein, wobei n die Anzahl der Dezimalstellen ist, und das wird auf einer Binärmaschine niemals der Fall sein!
– Clifford
4. Mai 2010 um 21:34 Uhr
jfs
Es kann von Vorteil sein, es zu verwenden ohne Vorzeichen ganze Zahlen mit explizit Größen in diesem Fall:
| tut ‘bitweise oder’ (logisches ODER auf Bits der Operanden).
0b0101 | 0b1001 -> 0b1101
Brillant. Jemand, der nicht nur weiß, wie man die C99-Typen mit expliziten Größen verwendet, sondern der auch versteht, wie man die verwandten verwendet printf Makros. +10, wenn ich könnte. SO-ers, vereinigt euch! Diese Antwort verdient eine Top-Abrechnung!
– Norman Ramsey
5. Mai 2010 um 0:11 Uhr
Könnte jemand aufschlüsseln, was diese Zeile bedeutet? uint64_t i = (uint64_t) MostSignificantWord << 32 | am wenigsten signifikantes Wort; Und was ist der PRIu64? Mein Compiler scheint es nicht zu mögen, sagt "expected ) nach PRIu64.
– bei
5. Mai 2010 um 15:59 Uhr
@Bei337: inttypes.h ist ein Teil des C99-Standards. Es definiert Formatbezeichner für printf/scanf wie zum Beispiel PRIu64 und es beinhaltet stdint.h das definiert typedefs wie uint32_t. Wenn Sie MSVC++/Windows verwenden, dann nehmen Sie inttypes.h aus code.google.com/p/msinttypes
– jfs
5. Mai 2010 um 16:33 Uhr
@Bei337: Es könnte helfen, wenn Sie den Code als C-Code kompilieren (nicht als C++). C++ erfordert __STDC_FORMAT_MACROS zu verwenden definiert werden PRI.. Makros.
– jfs
5. Mai 2010 um 20:52 Uhr
@PremalShah: uint32_t lo = (uint32_t)n, hi = (n >> 32);wo n ist ein unit64_t Variable.
– jfs
30. August 2012 um 14:16 Uhr
zweiwk
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
<< 32 wird nicht richtig funktionieren, wenn mostSignificantWord ist eine 32-Bit-Ganzzahl. Es muss zuerst in einen 64-Bit-Typ umgewandelt werden. Übrigens in g++ long und long long sind beide 8 Bytes.
– Alex Korban
4. Mai 2010 um 21:25 Uhr
@Alex: in g++ auf x64, long ist 64 Bit. Auf x86 sind es 32 Bit.
– Steve Jessop
4. Mai 2010 um 22:27 Uhr
Bitte verwenden Sie C99-Typen uint32_t und uint64_t. Deshalb sind sie da.
– Norman Ramsey
5. Mai 2010 um 0:09 Uhr
Die Eingänge sind unsignedalso sollte die Ausgabe nicht auch sein, wenn das OP nichts anderes sagt? long long für sich impliziert signed long long int.
– Unterstrich_d
1. Januar 2019 um 22:38 Uhr
meine aufnahme:
unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>
unsigned long long data64;
data64 = (unsigned long long) high << 32 | low;
printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */
Ein anderer Ansatz:
unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>
unsigned long long data64;
unsigned char * ptr = (unsigned char *) &data;
memcpy (ptr+0, &low, 4);
memcpy (ptr+4, &high, 4);
printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */
Beide Versionen funktionieren und haben eine ähnliche Leistung (der Compiler optimiert die memcpy weg).
Die zweite Version arbeitet nicht mit Big-Endian-Zielen, aber otoh, es nimmt dem Rätselraten, ob die Konstante 32 32 oder 32ull sein soll, ein Ende. Etwas, bei dem ich mir nie sicher bin, wenn ich Verschiebungen mit Konstanten größer als 31 sehe.
Es ist unerheblich, ob der Verschiebungsbetrag konstant ist 32 oder 32ULL, da beide den gleichen Wert haben und das ist alles, was für die Verschiebung verwendet wird. Solange der zu verschiebende Wert den Typ hat unsigned long longalles ist in Ordnung.
– Café
4. Mai 2010 um 22:00 Uhr
Warum überhaupt die nicht-portable Lösung zeigen? Jetzt wird es jemand kopieren, und später wird der Code in eine andere Anwendung verschoben, und irgendwann wird etwas kaputt gehen und es wird ewig dauern, ihn zu debuggen.
– Adrian McCarthy
4. Mai 2010 um 22:23 Uhr
Verwenden Sie die C99-Typen mit expliziten Größen. Deshalb sind sie da.
– Norman Ramsey
5. Mai 2010 um 0:10 Uhr
caiohamamura
Es gibt eine andere Möglichkeit, Arrays und Zeiger zu verwenden:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
// Two uint32_t to one uint64_t
uint32_t val1[2] = {1000, 90000};
uint64_t *val1_u64_ptr = (uint64_t*)val1; //intermediate pointer cast to avoid Wstrict-aliasing warnings
uint64_t val2 = *val1_u64_ptr;
printf("val2: %" PRIu64 "\n", val2);
// val2: 386547056641000
// back to uint32_t array from uint64_t
uint64_t val3 = 386547056641000ull;
uint32_t *val4 = (uint32_t*)&val3;
printf("val4: %" PRIu32 ", %" PRIu32 "\n", val4[0], val4[1]);
// val4: 1000, 90000
return 0;
}
Dieser Code ist für mich viel einfacher zu verstehen und zu lesen. Sie erstellen nur einen zusammenhängenden Raum im Speicher mit zwei 32-bit unsigned int und dann wird dieser selbe Speicherplatz als Single gelesen 64-bit unsigned int Wert und umgekehrt. Es sind keine Operationen beteiligt, nur der Speicher wird als unterschiedliche Typen gelesen.
BEARBEITEN
Ich habe vergessen zu erwähnen, dass dies großartig ist, wenn Sie bereits eine haben 64-bit array von irgendwo lesen dann könnte man alles problemlos nachlesen 32-bit array Paare:
#include <stdio.h>
#include <inttypes.h>
int main() {
uint64_t array64[] = {
386547056641000ull,
93929935171414ull,
186655006591110ull,
73141496240875ull,
161460097995400ull,
351282298325439ull,
97310615654411ull,
104561732955680ull,
383587691986172ull,
386547056641000ull
};
int n_items = sizeof(array64) / sizeof(array64[0]);
uint32_t* array32 = (uint32_t*)&array64;
for (int ii = 0; ii < n_items * 2; ii += 2) {
printf("[%" PRIu32 ", %" PRIu32 "]\n", array32[ii], array32[ii + 1]);
}
return 0;
}
Sie könnten dies tun, indem Sie die 32-Bit-Werte an die richtigen Stellen im Speicher schreiben:
unsigned long int data64;
data64=lowerword
*(&((unsigned int)data64)+1)=upperword;
Dies ist jedoch maschinenabhängig, zum Beispiel funktioniert es auf Big-Endian-Prozessoren nicht korrekt.
könnten Sie Ihre Antwort näher erläutern und erklären
– Taube
19. Oktober 2012 um 11:04 Uhr
Dies funktioniert nur auf Little-Endian-Maschinen. Eine weitere Annahme ist, dass unsigned long 64 Bit und unsigned int 32 Bit beträgt (kann uint32 und uint64 verwenden). jetzt die Erklärung data64=lowerword dies wird das untere Wort in die unteren Bytes von data64 kopieren. (unsigned int) data64 konvertiert es in 32 Bit. &((unsigned int)data64) gibt mir die Adresse vom Typ unsigned int das Hinzufügen von 1 wird die Adresse zu den höheren Bytes von data64 inkrementieren schließlich * davon speichert das obere Wort in diesen höheren Bytes.
– mohit
20. Oktober 2012 um 9:30 Uhr
Dies hat ein undefiniertes Verhalten; es verstößt gegen striktes Aliasing. Verwenden memcpy wenn Sie dies tun möchten, oder besser gar nicht. Compiler verstehen ((uint64_t)a<<32) | b
– Peter Cordes
5. Juni 2019 um 2:00 Uhr
13699900cookie-checkWie kombiniert man zwei 32-Bit-Ganzzahlen zu einer 64-Bit-Ganzzahl?yes
Ihre Methode würde nur Sinn machen, wenn Sie %8.8X als Formatbezeichner verwenden, um die Hexadezimalwerte der Wörter zu verketten. Damit es dezimal funktioniert, müsste der maximale ganzzahlige Wert (10^n)-1 sein, wobei n die Anzahl der Dezimalstellen ist, und das wird auf einer Binärmaschine niemals der Fall sein!
– Clifford
4. Mai 2010 um 21:34 Uhr