memcpy将ff ff ff添加到一个字节的开头

时间:2010-08-18 13:46:07

标签: c++ memcpy

我有一个这样的数组:

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

发生了什么事?

4 个答案:

答案 0 :(得分:13)

我已将您的代码转换为完整的可编译示例。我还在我的环境中添加了第三个“正常”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类型时才会附加'extra'ff。原因是当memcpy填充已签名的char数组时,具有高位集的值现在对应于负char值。传递给printf后,char会提升为int类型,这实际上意味着符号扩展。

%x以十六进制打印它们,就像它们是unsigned int一样,但是当参数作为int传递时,行为在技术上是未定义的。通常在二进制补码机器上,行为与使用mod 2 ^ N算术的无符号转换的标准相同(其中N是unsigned int中的值位数)。由于该值仅为“略微”负(来自窄签名类型),因此转换后该值接近最大可能的unsigned int值,即它具有许多前导1(以二进制形式) )或以十六进制领先f

答案 1 :(得分:4)

问题不是memcpy(除非你的char类型确实是32位,而不是8位),它在打印时看起来更像是整数符号扩展。

您可能希望更改printf以显式使用无符号字符转换,即

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

作为猜测,您的编译器/优化器可能正在处理array(其大小和内容在编译时已知)和array2不同,首先将常量值推入堆栈并错误地在第二个中推送符号扩展值。

答案 2 :(得分:4)

你应该掩盖更高的位,因为在调用varargs函数时你的字符将扩展到int大小:

printf("%x %x %x %x %x %x", array[0] & 0xff,  // ..

答案 3 :(得分:2)

%x格式需要整数类型。尝试使用cast:

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

编辑: 由于我的帖子有新的评论,我想添加一些信息。在调用printf函数之前,编译器会生成代码,这些代码会推送参数的堆栈变量列表(...)。编译器对printf格式代码一无所知,并根据类型推送参数。 printf根据格式化字符串从堆栈中收集参数。因此,array [i]被推送为char,并由printf作为int处理。因此,如果参数类型与格式规范不完全匹配,使用printf / scanf函数进行转换总是好主意。