У меня есть регистр количества, который составлен из двух 32-разрядных целых чисел без знака, один для более высоких 32 битов значения (старшее значащее слово), и другой для более низких 32 битов значения (младшее значащее слово).
Каков лучший способ в C, чтобы объединить эти два 32-разрядных целых числа без знака и затем отобразиться как большое количество?
В определенном:
leastSignificantWord = 4294967295; //2^32-1
printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);
Это распечатало бы прекрасный.
Когда число увеличено к 4294967296, у меня есть оно так очистки leastSignificantWord к 0, и mostSignificantWord (0 первоначально) равняется теперь 1. Целый счетчик должен теперь читать 4294967296, но прямо сейчас он просто читает 10, потому что я просто конкатенирую 1 от mostSignificantWord и 0 от leastSignificantWord.
Как я должен заставить его отобразиться 4294967296 вместо 10?
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
В этом случае может быть выгодно использовать целые числа без знака с явными размерами:
#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;
}
Выход { {1}}
4294967296
(uint64_t) mostSignificantWord << 32 | lessSignificantWord
(typename)
выполняет приведение типов в C. Это изменяет тип данных значения на typename
.
(uint64_t) 0x00000001 -> 0x0000000000000001
<<
выполняет сдвиг влево . В C сдвиг влево для целых чисел без знака выполняет логический сдвиг .
0x0000000000000001 << 32 -> 0x0000000100000000
|
выполняет «побитовое ИЛИ» (логическое ИЛИ над битами операндов).
0b0101 | 0b1001 -> 0b1101
мой вариант:
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 */
Другой подход:
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 */
Обе версии работают, и у них будет схожая производительность (компилятор оптимизирует memcpy).
Вторая версия не работает с целевыми числами с прямым порядком байтов, но в ней нет необходимости гадать, должна ли константа 32 быть 32 или 32ull. Что-то я никогда не уверен, когда вижу сдвиги с константами больше 31.
Вместо того, чтобы печатать десятичное число, я часто печатаю в шестнадцатеричном.
Таким образом ...
printf ("0x%x%08x\n", upper32, lower32);
В качестве альтернативы, в зависимости от архитектуры, платформы и компилятора, иногда можно обойтись чем-то вроде ...
printf ("%lld\n", lower32, upper32);
или
printf ("%lld\n", upper32, lower32);
Однако этот альтернативный метод сильно зависит от машины (endian -ness, а также 64 vs 32 бит, ...) и вообще не рекомендуется.
Надеюсь, это поможет.