Как выполнить сдвиг влево от 64 бит в C

Я пытаюсь скопировать два 32-битных значения в один 64-битный адрес. Одно DWORD — это старшие 32 бита, а второе — младшие 32 бита. Я пробовал следующее, но операнд сдвига в 64-битных значениях не работает:

UINT64 a = 0x12341234;
UINT64 b = 0x00003800;

Мне нужно значение: 0x0000380012341234

Так я и сделал:

printf("b 0x%016x\n", b);
b = ((UINT64)b) << 20;
printf("b 0x%016x\n", b); 

и отпечатки, которые я получаю:

b 0x0000000000003800

b 0x0000000080000000

Я пробовал переключаться на разные числа (снова 10 и 10, или 32, или 0x20), но у меня ничего не получалось.

Почему не работает переход на старшие 32 бита UINT64, и как еще я могу это сделать?


person user1016179    schedule 25.05.2017    source источник
comment
изменить %016x на %016llx   -  person r3mainer    schedule 25.05.2017
comment
Сдвиг работает нормально, проблема в его печати.   -  person Barmar    schedule 25.05.2017


Ответы (4)


Это единственная проблема с типом printf(). Я пробовал, работает нормально.

#include <stdio.h>
#include <stdlib.h>

#define UINT64 unsigned long long

int main()
{
    UINT64 a = 0x12341234;
    UINT64 b = 0x00003800;
    printf("b 0x%016llx\n", (unsigned long long)b);
    b = ((UINT64)b) << 32;
    printf("b 0x%016llx\n",(unsigned long long) b);
    system("pause");
}

Надеюсь, поможет. :)

person Vishwajeet Vishu    schedule 25.05.2017
comment
Да очень верно. На самом деле это уже упоминалось в вопросе, поэтому я не удалил его. - person Vishwajeet Vishu; 25.05.2017
comment
@VishwajeetVishu-Все еще нужно добавить? - person Peter; 25.05.2017
comment
@Peter, то, как был задан вопрос, казалось, достаточно умно - person Vishwajeet Vishu; 26.05.2017

Ваш спецификатор формата сообщает printf, что аргумент является нормальным (вероятно, 32-битным) int, поэтому он отсекает верхние 32 бита (поскольку ваш компьютер должен иметь обратный порядок байтов).

Вы можете использовать %llx, но если это так, у меня возникнет соблазн также привести аргумент к unsigned long long.

printf("b 0x%016llx\n", (unsigned long long)b);

C11 также определяет некоторые спецификаторы формата с фиксированной шириной в inttypes.h, чтобы сделать его безопасным без приведения — PRIx64 это то, что вам нужно.

person JeremyP    schedule 25.05.2017

Вы можете преобразовать константу в unsigned long long, но также вы можете сказать лексеру сделать ее прямо unsigned long long такой

printf("%x\n", 0xnnnnnnnnULL);

В этом случае лексер сгенерирует c-лексему целочисленного типа с типом unsigned long long и не требует приведения.

person alinsoar    schedule 25.05.2017

Чтобы добавить к сообщению Вишваджита, нужно, конечно, добавить:

#include <stdio.h>
#include <stdlib.h>

#define UINT64 unsigned long long

int main()
{
    UINT64 a = 0x12341234;
    UINT64 b = 0x00003800;
    printf("b 0x%016llx\n", (unsigned long long)b);
    b <<= 32;
    b += a;
    printf("b 0x%016llx\n",(unsigned long long) b);
    system("pause");
}
person Peter    schedule 25.05.2017