У меня есть массив, который выглядит примерно так:
unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'};
unsigned char array2[6];
Когда я использую memcpy:
memcpy(array2, array, 6);
И распечатываю их оба:
printf("%x %x %x %x %x %x", array[0], // ... etc
printf("%x %x %x %x %x %x", array2[0], // ... etc
один выводит как:
c0 3f e 54 e5 20
, а другой печатает
ffffffc0 3f e 54 ffffffe5 20
что случилось?
Я превратил ваш код в законченный компилируемый пример. Я также добавил третий массив «нормального» char
, который в моей среде подписан.
#include <cstring>
#include <cstdio>
using std::memcpy;
using std::printf;
int main()
{
unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'};
unsigned char array2[6];
char array3[6];
memcpy(array2, array, 6);
memcpy(array3, array, 6);
printf("%x %x %x %x %x %x\n", array[0], array[1], array[2], array[3], array[4], array[5]);
printf("%x %x %x %x %x %x\n", array2[0], array2[1], array2[2], array2[3], array2[4], array2[5]);
printf("%x %x %x %x %x %x\n", array3[0], array3[1], array3[2], array3[3], array3[4], array3[5]);
return 0;
}
Мои результаты оказались такими, как я ожидал.
c0 3f e 54 e5 20
c0 3f e 54 e5 20
ffffffc0 3f e 54 ffffffe5 20
Как видите, "extra" ff
добавляются только тогда, когда массив имеет тип char со знаком. Причина в том, что когда memcpy
заполняет массив подписанных char
, значения с установленным старшим битом теперь соответствуют отрицательным значениям char
. При передаче в printf
char
повышается до типов int
, что фактически означает знаковое расширение.
% x
печатает их в шестнадцатеричном формате, как если бы они были unsigned int
, но поскольку аргумент был передан как int
, поведение технически не определено. Обычно на машине с дополнением до двух поведение такое же, как и при стандартном преобразовании со знаком в беззнаковое, которое использует арифметику mod 2 ^ N (где N - количество битов значения в unsigned int
). Поскольку значение было лишь «слегка» отрицательным (происходило из узкого знакового типа), после преобразования значение близко к максимально возможному unsigned int
значению, то есть оно имеет много ведущих 1
's (в двоичном формате) или ведущий f
в шестнадцатеричном формате.
Вы должны замаскировать старшие биты, так как ваши символы будут расширены до размера int
при вызове функции varargs:
printf("%x %x %x %x %x %x", array[0] & 0xff, // ..
Проблема не в memcpy
(если ваш тип char действительно 32 бита, а не 8), это больше похоже на расширение знака целого числа при печати.
вы можете захотеть изменить свой printf, чтобы явно использовать преобразование беззнаковых символов, т.е.
printf("%hhx %hhx...", array2[0], array2[1],...);
Предположительно, ваш компилятор / оптимизатор может по-разному обрабатывать массив
(размер и содержимое которого известны во время компиляции) и массив2
, помещая значения констант в стек. во-первых, и ошибочно нажимая знак расширенных значений во втором.
Формат% x предполагает целочисленный тип. Попробуйте использовать приведение:
printf("%x %x %x %x %x %x", (int)array2[0], ...
Изменить: Поскольку к моему сообщению есть новые комментарии, я хочу добавить некоторую информацию. Перед вызовом функции printf компилятор генерирует код, который помещает в список параметров стека переменную (...). Компилятор ничего не знает о кодах формата printf и передает параметры в соответствии с их типом. printf собирает параметры из стека в соответствии со строкой форматирования. Итак, array [i] помещается как char и обрабатывается printf как int. Следовательно, всегда рекомендуется производить приведение, если тип параметра не соответствует в точности спецификации формата, работая с функциями printf / scanf.