web-dev-qa-db-fra.com

Comment combiner deux entiers 32 bits en un entier 64 bits?

J'ai un registre de comptage, qui est composé de deux entiers non signés 32 bits, l'un pour les 32 bits supérieurs de la valeur (mot le plus significatif) et l'autre pour les 32 bits inférieurs de la valeur (mot le moins significatif).

Quelle est la meilleure façon en C de combiner ces deux entiers non signés 32 bits et de les afficher ensuite en grand nombre?

En particulier:

leastSignificantWord = 4294967295; //2^32-1

printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);

Cela s'imprimerait bien.

Lorsque le nombre est incrémenté à 4294967296, je l'ai donc le moins de mots importants à 0 et le plus de mots significatifs (0 au départ) est maintenant 1. Le compteur entier devrait maintenant lire 4294967296, mais pour le moment il ne fait que 10, parce que je concatène simplement 1 de mostSignificantWord et 0 de lessSignificantWord.

Comment dois-je faire afficher 4294967296 au lieu de 10?

22
jiake
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
34
twk

Il peut être avantageux d'utiliser des entiers non signés avec des tailles explicites dans ce cas :

#include <stdio.h>
#include <inttypes.h>

int main(void) {
  uint32_t leastSignificantWord = 0;
  uint32_t mostSignificantWord = 1;
  uint64_t i = (uint64_t) mostSignificantWord << 32 | leastSignificantWord;
  printf("%" PRIu64 "\n", i);

  return 0;
}

4294967296

Panne de (uint64_t) mostSignificantWord << 32 | leastSignificantWord

  • (typename) fait transtypage en C. Il change le type de données de valeur en typename.

    (uint64_t) 0x00000001 -> 0x0000000000000001

  • << fait décalage vers la gauche . En C, le décalage à gauche sur les entiers non signés effectue décalage logique .

    0x0000000000000001 << 32 -> 0x0000000100000000

left logical shift

61
jfs

mon avis:

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 */

Une autre approche:

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 */

Les deux versions fonctionnent, et elles auront des performances similaires (le compilateur optimisera la mémoire).

La deuxième version ne fonctionne pas avec les cibles big-endian mais otoh cela enlève le devinette si la constante 32 doit être 32 ou 32ull. Quelque chose dont je ne suis jamais sûr quand je vois des changements avec des constantes supérieures à 31.

3

Ce code fonctionne lorsque upper32 et lower32 sont négatifs:

data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);
1
AIMrus

Au lieu d'essayer d'imprimer en décimal, j'imprime souvent en hexadécimal.

Donc ...

printf ("0x%x%08x\n", upper32, lower32);

Alternativement, selon l'architecture, la plate-forme et le compilateur, vous pouvez parfois vous en sortir avec quelque chose comme ...

printf ("%lld\n", lower32, upper32);

ou

printf ("%lld\n", upper32, lower32);

Cependant, cette méthode alternative est très dépendante de la machine (endian-ness, ainsi que 64 vs 32 bits, ...) et en général n'est pas recommandée.

J'espère que cela t'aides.

1
Sparky

Il existe une autre façon d'utiliser les tableaux et les pointeurs:

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint32_t val1[2] = {1000, 90000};
    uint64_t *val2 = (uint64_t*)val1;
    printf("val2 %llu\n", *val2);

    // back to uint32_t from uint64_t
    uint32_t *val3 = (uint32_t*)val2;
    printf("val3: %u, %u\n", val3[0], val3[1]);

    return 0;
}
0
caiohamamura