将int复制到不同的内存位置,接收比预期更多的字节

时间:2014-04-29 15:42:01

标签: c pointers

在获得4字节int的长度后,尝试预先挂起2字节的消息长度。我使用memcpy复制int的2个字节。当我查看我复制的第二个字节时,它是预期的,但访问第一个字节实际上打印了4个字节。

我希望dest [0]和dest [1]都包含int的1个字节。无论它是一个重要的字节,还是顺序被切换......我可以在memcpy上抛出一个偏移量或者反转0和1.它不必是可移植的,我只是想它可以工作。

Windows中使用LoadRunner和Ubuntu使用GCC也会发生同样的错误 - 所以我至少试图排除可移植性。

我不确定我哪里出错了。我怀疑这与我最近没有使用指针有关?有没有更好的方法将int转换为short,然后将其放在缓冲区的前2个字节中?

char* src;
char* dest;
int len = 2753; // Hex - AC1
src=(char*)malloc(len);
dest=(char*)malloc(len+2);

memcpy(dest, &len, 2);
memcpy(dest+2, src, len);

printf("dest[0]: %02x", dest[0]); 
// expected result: c1
// actual result: ffffffc1

printf("dest[1]: %02x", dest[1]); 
// expected result: 0a
// actual result: 0a

4 个答案:

答案 0 :(得分:2)

你不能只从一个四字节对象中取一个随机的两个字节,并将其称为一个简短的转换。

在执行memcpy之前,您需要将int复制到两个字节的int中。

但实际上,这也不是最好的方法,因为你无法控制整数的字节顺序。

您的代码应如下所示:

dest[0] = ((unsigned)len >> 8) & 0xFF;
dest[1] = ((unsigned)len) & 0xFF;

那应该用网络字节顺序写出来,也就是大端。所有标准网络协议都使用此字节顺序。

我还要添加以下内容:

assert( ((unsigned)len & 0xFFFF0000) == 0 ); // should be nothing in the high bytes

答案 1 :(得分:2)

首先,您错误地使用了printf。此

printf("dest[0]: %02x", dest[0]); 

x中使用printf格式说明符。 x格式说明符需要类型为unsigned int的参数。不是char,而是unsigned int,只有unsigned int(或者int具有非负值)。

您提供的即时参数的类型为char,可能已在您的平台上签名。这意味着您的dest[0]包含-63。类型为char的可变参数会自动提升为int类型,这会将0xc1转换为0xffffffc1(作为-63中已签名的int表示形式}})。由于printf需要unsigned int值而您传递的是负int值,因此行为未定义。您看到的打印输出只不过是未定义行为的表现。这没有意义。

在这种情况下打印dest[0]的一种正确方法是

printf("dest[0]: %02x", (unsigned) dest[0]); 

我非常确定输出仍为ffffffc1,但在这种情况下,0xffffffc1是从负-63值到{{1}的整数转换的完美预期结果}类型。这里没什么不寻常的。

或者你可以做

unsigned int

应该为您提供所需的printf("dest[0]: %02x", (unsigned char) dest[0]); 输出。请注意,转换为c1也会发生在这种情况下,但由于原始值为正(int),因此转换为193的结果也是正值int 1}}正常工作。

最后,如果您想直接使用原始内存,从一开始就使用正确的类型printf。不是unsigned char,而是char

其次,类型unsigned char的对象可能容易占用两个以上的8位字节。根据平台,int0xA值可能最终位于该0xC1对象占用的内存区域的完全不同的部分。您不应期望复制int对象的前两个字节将专门复制int部分。

答案 2 :(得分:0)

你假设" int"是两个字节。你有什么理由呢?您的代码非常难以移植。

你做了另一个假设" char"没有签名。你有什么理由呢?同样,您的代码非常难以移植。

您对int中的字节顺序做了另一个假设。你有什么理由呢?同样,您的代码非常难以移植。

答案 3 :(得分:0)

而不是文字2,使用sizeof(int)。永远不要硬编码类型的大小。

如果此代码应该是可移植的,则不应使用int,而应使用固定大小的数据类型。 如果您需要16位,则可以使用int16_t

此外,字符的打印需要转换为无符号。现在,char被上传到int,并且符号被扩展。这给出了初始的FFFF