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

что случилось?

7
задан Hock 18 August 2010 в 13:46
поделиться

4 ответа

Я превратил ваш код в законченный компилируемый пример. Я также добавил третий массив «нормального» 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 в шестнадцатеричном формате.

13
ответ дан 6 December 2019 в 07:49
поделиться

Вы должны замаскировать старшие биты, так как ваши символы будут расширены до размера int при вызове функции varargs:

printf("%x %x %x %x %x %x", array[0] & 0xff,  // ..
4
ответ дан 6 December 2019 в 07:49
поделиться

Проблема не в memcpy (если ваш тип char действительно 32 бита, а не 8), это больше похоже на расширение знака целого числа при печати.

вы можете захотеть изменить свой printf, чтобы явно использовать преобразование беззнаковых символов, т.е.

printf("%hhx %hhx...", array2[0], array2[1],...);

Предположительно, ваш компилятор / оптимизатор может по-разному обрабатывать массив (размер и содержимое которого известны во время компиляции) и массив2 , помещая значения констант в стек. во-первых, и ошибочно нажимая знак расширенных значений во втором.

4
ответ дан 6 December 2019 в 07:49
поделиться

Формат% x предполагает целочисленный тип. Попробуйте использовать приведение:

printf("%x %x %x %x %x %x", (int)array2[0], ...

Изменить: Поскольку к моему сообщению есть новые комментарии, я хочу добавить некоторую информацию. Перед вызовом функции printf компилятор генерирует код, который помещает в список параметров стека переменную (...). Компилятор ничего не знает о кодах формата printf и передает параметры в соответствии с их типом. printf собирает параметры из стека в соответствии со строкой форматирования. Итак, array [i] помещается как char и обрабатывается printf как int. Следовательно, всегда рекомендуется производить приведение, если тип параметра не соответствует в точности спецификации формата, работая с функциями printf / scanf.

2
ответ дан 6 December 2019 в 07:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: