2010-08-13 4 views
1

J'utilise une bibliothèque qui renvoie une structure avec un horodatage qui est représenté par deux (TimestampHi, TimestampLo) unsigned long s. J'ai à peu près besoin seulement de l'horodatage imprimé comme %llu dans printf.Comment utiliser deux entiers 32 bits en tant que 64 bits dans C?

Quel est le moyen le plus simple d'obtenir les données de ces deux entrées et de les utiliser correctement comme uint64_t?

+2

Vous devriez probablement étiqueter ceci avec votre OS/plate-forme. Bien que vous supposiez que cela soit le cas dans votre situation, toutes les plates-formes 64 bits n'utilisent pas une longueur de 32 bits, d'autres utilisent 64 bits. –

+2

% llu n'est pas le bon format pour uint64_t. Convertissez la valeur en unsigned long long et utilisez% llu, utilisez la macro PRIu64 de ou transtypez en uintmax_t et utilisez% ju. – jilles

Répondre

10

En supposant que unsigned long long est un type 64 bits sur votre plate-forme

assert(sizeof(unsigned long) * CHAR_BIT == 32); 
assert(sizeof(unsigned long long) * CHAR_BIT == 64); 
// Static asserts are more appropriate in cases like this 

unsigned long long Timestamp = TimestampHi; 
Timestamp <<= 32; Timestamp += TimestampLo; 

Et puis imprimez la valeur Timestamp.

Même chose comme un one-liner

unsigned long long Timestamp = ((unsigned long long) TimestampHi << 32) + TimestampLo; 

ou simplement

printf("%llu\n", ((unsigned long long) TimestampHi << 32) + TimestampLo); 

Si vous souhaitez abstraire votre code d'exploitation à base de bits, l'expression peut être réécrite comme

TimestampHi * ((unsigned long long) ULONG_MAX + 1) + TimestampLo 
+0

Je ne serais probablement pas déranger avec le '* CHAR_BIT', mais +1 pour la correction atroce. (Qui a des octets non-8 bits?) – zwol

+0

@Zack: Divers DSP ont des octets de 16 ou 32 bits. @AndreyT: est-ce que 'unsigned long long' est garanti pour ne pas avoir de bits de remplissage? –

+0

@Steve Jessop: Ni «unsigned long», ni «unsigned long long» ne garantissent pas de bits de remplissage. Donc, bien sûr, mes affirmations ne vérifient pas vraiment ce qu'il était censé vérifier. Ce qui précède est écrit sous l'hypothèse qu'ils n'ont pas de bits de remplissage et/ou que 'unsigned long long' est suffisamment grand pour stocker un produit de deux valeurs arbitraires' unsigned long'. – AnT

1

Andrey a répondu ce que vous faites si vous avez certains type 64 bits, mais peut-être que vous avez seulement des types 32 bits. Dans ce cas, vous avez besoin d'une bibliothèque d'entiers multi-précision. Le GNU MP library est excellent, mais peut être exagéré pour vos besoins. I8lib implémente l'arithmétique des nombres entiers de précision "double" (c'est-à-dire pas plus de 64 bits) et pourrait vous faire du bien, mais je ne l'ai jamais utilisé.

+0

Un compilateur sans type 64 bits n'est pas conforme (à la norme C actuelle). –

+0

@R: un compilateur sans type 64 bits est courant dans la programmation intégrée – tomlogic

+0

@R Et s'il écrit le compilateur pour une machine 32 bits et doit écrire une bibliothèque d'exécution du compilateur qui implémente l'arithmétique 64 bits? –

0

Si la réponse est inférieure à 2^49, et que les nombres de 64 bits ne sont pas disponibles, qu'en est-il de printf ("% 1.0f", 4294967296.0 * upper_part + lower_part)? Cela ne fonctionnerait pas sur les plates-formes où un double est inférieur à 64 bits, mais cela fonctionnerait sur de nombreuses plates-formes sans ints 64 bits.

+0

Pourquoi ne pas séparer l'impression des 2 parties en utilisant 2 appels à 'sprintf', puis les ajouter avec l'addition ASCII? De cette façon, vous avez juste besoin de 32 bits de précision dans la mantisse. D'autre part, il est possible que 'printf 'de votre système suce et imprime juste des ordures (par exemple des zéros) dans les endroits bas après qu'il ait imprimé suffisamment de chiffres pour déterminer de façon unique le nombre. (Voir ma question http://stackoverflow.com/questions/3215235/how-do-you-print-the-exact-value-of-a-floating-point-number) –

4
unsigned long long t = (unsigned long long)hi << 32 | lo; 
printf("%ull\n", t); 

Notez que j'utilise unsigned long long au lieu de uint64_t parce qu'il est

  1. garanti à au moins 64 bits, et
  2. facile à imprimer avec printf - vous n'avez pas besoin PRIu64 macro, et
  3. vous avez mentionné %ull dans la question.

Cependant, si vous voulez soutenir MSVC (qui est loin d'être conforme aux normes modernes), vous pourriez être mieux avec:

uint64_t t = (uint64_t)hi << 32 | lo; 
printf("%" PRIu64 "\n", t); 

De cette façon, vous pouvez vous assurer (via le remplacement des disparus en-têtes système) que uint64_t est correctement défini en tant que type non signé 64 bits de MSVC et PRIu64 est défini comme le spécificateur de format printf approprié pour l'imprimer.

+0

+1 pour une solution portable (pour les plateformes qui supporte un int 64 bits). – tomlogic

Questions connexes