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

C 正在将int复制到不同的内存位置,接收到比预期更多的字节,c,pointers,C,Pointers,在获取4字节int中的长度后,尝试预挂起2字节的消息长度。我使用memcpy复制int中的2个字节。当我查看复制的第二个字节时,正如预期的那样,但访问第一个字节实际上会打印4个字节 我希望dest[0]和dest[1]都包含int的1个字节。无论它是有效字节还是顺序被切换。。。我可以在memcpy上输入一个偏移量,或者反转0和1。它不必是便携式的,我只希望它能工作 同样的错误也发生在使用LoadRunner的Windows和使用GCC的Ubuntu中——所以我至少尝试排除了可移植性的原因 我不确

在获取4字节int中的长度后,尝试预挂起2字节的消息长度。我使用memcpy复制int中的2个字节。当我查看复制的第二个字节时,正如预期的那样,但访问第一个字节实际上会打印4个字节

我希望dest[0]和dest[1]都包含int的1个字节。无论它是有效字节还是顺序被切换。。。我可以在memcpy上输入一个偏移量,或者反转0和1。它不必是便携式的,我只希望它能工作

同样的错误也发生在使用LoadRunner的Windows和使用GCC的Ubuntu中——所以我至少尝试排除了可移植性的原因

我不确定我错在哪里。我怀疑这与我最近没有使用指针有关?有没有更好的方法将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

假设“int”是两个字节。你有什么理由这样做?你的代码非常不可移植

您还可以假设“char”是无符号的。你有什么理由这样做?同样,您的代码非常不可移植


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

假设“int”是两个字节。你有什么理由这样做?你的代码非常不可移植

您还可以假设“char”是无符号的。你有什么理由这样做?同样,您的代码非常不可移植


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

使用sizeof(int)代替文本2。永远不要硬编码类型的大小

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


此外,字符的打印需要对未签名字符进行强制转换。现在,字符被上置为int,符号被扩展。这将使用sizeof(int)而不是literal 2给出初始FFFF。永远不要硬编码类型的大小

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


此外,字符的打印需要对未签名字符进行强制转换。现在,字符被上置为int,符号被扩展。这给出了初始FFFF的

,您不能只是从一个四字节的对象中随机抽取两个字节,并将其称为cast to short

在执行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

您不能只是从一个四字节对象中随机抽取两个字节,并将其称为cast to short

在执行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

首先,您不正确地使用了
printf
。这个

printf("dest[0]: %02x", dest[0]); 
printf
中使用
x
格式说明符
x
格式说明符需要类型为
unsigned int
的参数。不是
char
,而是
unsigned int
,并且只有
unsigned int
(或者是一个非负值的
int

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

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

printf("dest[0]: %02x", (unsigned) dest[0]); 
我很确定输出仍然是
ffffffc1
,但在这种情况下
0xffffc1
是从负
-63
值到
无符号int
类型的整数转换的完美预期结果。这里没什么不寻常的

或者你也可以这样做

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

最后,如果您想直接使用原始内存,从一开始就应该使用
unsigned char
。不是
字符
,而是
无符号字符

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