Memcpy добавляет ff ff ff в начало байта
Вопрос
У меня есть массив, который такой:
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
Как видите, только когда массив подписанный тип Char, сделайте «дополнительный» ff
получить добавление. Причина в том, что когда memcpy
заполняет массив подписанного char
, значения с высоким набором бита теперь соответствуют отрицательному char
ценности. Когда передано printf
а char
продвигаются на int
Типы, которые эффективно означают расширение знака.
%x
печатает их в шестнадцатеричном unsigned int
, но как аргумент был принят как int
Поведение технически не определен. Как правило, на двухместной машине поведение такое же, как и стандартное, подписанное на беспигнированное преобразование, которое использует арифметику MOD 2^n (где n - количество бит значения в unsigned int
) Поскольку значение было лишь немного «слегка» отрицательным (исходя из узкого подписанного типа), преобразование после преобразования значения близко к максимально возможным unsigned int
ценность, т.е. у него много ведущих 1
S (в бинарном) или ведущем f
в гекс.
Другие советы
Проблема не memcpy
(Если ваш тип Char на самом деле не является 32 битами, а не 8), он больше похож на расширение знака целочисленного знака во время печати.
Возможно, вы захотите изменить свой Printf, чтобы явно использовать конверсию без подписи, т.е.
printf("%hhx %hhx...", array2[0], array2[1],...);
В качестве предположения, возможно, что ваш компилятор/оптимизатор обрабатывает array
(Размер и содержимое чьи array2
По -другому, в первую очередь наталкивая постоянные значения в стек и ошибочно выдвигая расширенные знаки во втором.
Вы должны замаскировать более высокие биты, так как ваш Chars будет расширен на int
размер при вызове функции Varargs:
printf("%x %x %x %x %x %x", array[0] & 0xff, // ..
%x Формат ожидает целочисленного типа. Попробуйте использовать кастинг:
printf("%x %x %x %x %x %x", (int)array2[0], ...
РЕДАКТИРОВАТЬ: Поскольку в моем посте есть новые комментарии, я хочу добавить некоторую информацию. Перед вызовом функции PrintF компилятор генерирует код, который нажимает на список переменных стека (...). Компилятор ничего не знает о кодах форматов printf и выдвигает параметры в соответствии с их типом. printf собирает параметры из стека в соответствии с форматированием строки. Итак, массив [i] выдвигается как ЧАР, и обрабатывается Printf как int. Следовательно, всегда хорошая идея сделать литью, если тип параметров не соответствует точно такой спецификации формата, работая с функциями printf/scanf.