C - скопировать символы значения ASCII в 64-битное целое число

Как мы все знаем, каждый печатный символ имеет свое значение ascii. Я пытаюсь преобразовать значение ascii из 8 символов в 64-битное целое число, но оно копирует только 32 бита.

char * ch = "AAAABBBB";
unsigned long int i;

//copy charater's ascii to 64 bits int
memcpy(&i, ch, 8);
printf("integer hold: 0x%x\n", i); 

Что-то не так с этим кодом?

Результат, который я ожидаю, был:

integer hold: 0x4141414142424242

но вывод был:

integer hold: 0x41414141

person REALFREE    schedule 05.02.2013    source источник
comment
Включите ваши предупреждения!   -  person Carl Norum    schedule 05.02.2013
comment
@CarlNorum И что именно это решит? Что касается компилятора, этот код просто прекрасен.   -  person Lundin    schedule 05.02.2013
comment
@Lundin, несоответствие строк формата printf вызывает неопределенное поведение. GCC и clang обнаружат и предупредят об этой проблеме. Clang даже дает предлагаемое решение!   -  person Carl Norum    schedule 06.02.2013
comment
@CarlNorum Где находится несоответствующая строка формата? GCC -Wall ничего не дает, и я не вижу ничего плохого в этом коде, кроме плохого выбора объявления указателя на строковый литерал как неконстантного. Печать беззнаковой длинной переменной с %x не является неопределенным поведением, даже если long больше, чем int. Насколько я знаю, взятие части unsigned long по любой причине всегда четко определено и не приведет к представлению ловушки.   -  person Lundin    schedule 06.02.2013
comment
%x для unsigned int, а не unsigned long int. Несоответствия всегда не определены, даже если некоторые или все реализации делают что-то разумное. Я возьму вывод предупреждений и вставлю сюда, когда в следующий раз буду за компьютером.   -  person Carl Norum    schedule 06.02.2013
comment
@Lundin, из clang для простой тестовой программы: example.c:6:20: предупреждение: формат указывает тип «unsigned int», но аргумент имеет тип «unsigned long» [-Wformat] И из GCC: example.c:6 : предупреждение: формат '%x' предполагает тип 'unsigned int', но аргумент 2 имеет тип 'long unsigned int'. В дополнение к предупреждению clang предлагает заменить %x на %lx.   -  person Carl Norum    schedule 06.02.2013
comment
@Lundin, я должен отметить, что мне даже не нужно было включать какие-либо флаги -W. Эти сообщения выводились по умолчанию с помощью GCC 4.2.1 (я знаю, старый, но я был на Mac) и clang 3.2.   -  person Carl Norum    schedule 06.02.2013


Ответы (3)


Если unsigned long действительно является 64-битным типом (вы можете вывести sizeof(unsigned long), чтобы проверить это), вам по-прежнему нужно использовать строку формата %lx для его печати.

Если unsigned long составляет 32 бита, вам, вероятно, придется прибегнуть к unsigned long long и использовать строку формата %llx.

От C11 7.20.6.1 The fprintf function:

o,u,x,X Аргумент unsigned int преобразуется в беззнаковое восьмеричное (o), беззнаковое десятичное (u) или беззнаковое шестнадцатеричное представление (x или X) в стиле dddd; буквы abcdef используются для преобразования x, а буквы ABCDEF — для преобразования X. Точность определяет минимальное количество отображаемых цифр; если преобразуемое значение может быть представлено меньшим количеством цифр, оно дополняется ведущими нулями. Точность по умолчанию равна 1. Результатом преобразования нулевого значения с нулевой точностью является отсутствие символов.

l (ell): указывает, что следующий спецификатор преобразования d, i, o, u, x или X применяется к аргументу long int или unsigned long int.

ll (ell-ell): указывает, что следующий спецификатор преобразования d, i, o, u, x или X применяется к аргументу long long int или unsigned long long int.

person paxdiablo    schedule 05.02.2013

long против long long.

В VC++ тип данных long по-прежнему составляет всего 32 бита.

И, конечно же, формат printf %x используется для int, который на большинстве платформ составляет 32 бита. Вам нужен %llx (или, возможно, %lx, если ваш long уже 64-битный).

person Some programmer dude    schedule 05.02.2013
comment
Я говорю о C, а не о VC++. И я уже проверил размер unsigned long int, который составляет 8 байт. - person REALFREE; 05.02.2013
comment
@REALFREE Пожалуйста, смотрите мой обновленный ответ. И вы не указали компилятор, а только язык (и язык C позволяет компиляторам иметь разную длину в битах для некоторых типов) - person Some programmer dude; 05.02.2013
comment
%u и %x являются взаимоисключающими, %ullx даст неотмеченное десятичное число, за которым следует буквальная строка llx. x по определению не имеет знака. Правильный формат: %llx или %lx. - person paxdiablo; 05.02.2013
comment
Как насчет 4 байтов в 64 бита? Например, c = AAAA и скопируйте его в unsigned long int. Я думал, что это будет 0x00000041414141 с форматом 0x%16lx, но он показывает как 0x 41414141 с пустым пространством. - person REALFREE; 05.02.2013
comment
@REALFREE Вы хотите установить ширину поля. См. printf справку. - person Some programmer dude; 05.02.2013
comment
@REALFREE, вам нужно дополнить это нулями, а не пробелами. Используйте %016lx (обратите внимание на начальный ноль). - person paxdiablo; 05.02.2013

%x используется для печати значения unsigned int и его 32-битного значения, поэтому вы получаете такой результат.

%d %i     Decimal signed integer.
%o        Octal integer.
%x %X     Hex integer.
%u        Unsigned integer.
%c        Character.
%s        String.
%f        double
%e %E     double.
%g %G     double.
%p        pointer.

& если вы хотите распечатать оставшиеся данные, попробуйте...

int *p;
p=(char *)(&i)+4;

printf("integer hold: 0x%x\n", i);
printf("integer hold: 0x%x\n",*p);
person akp    schedule 05.02.2013