正如标题所说,运行以下代码时,我得到一个“奇怪”的结果:
#include <stdio.h>
int main()
{
char buff[4] = {0x17, 0x89, 0x39, 0x40};
unsigned int* ptr = (unsigned int*)buff;
char a = (char)((*ptr << (0*8)) >> (3*8));
char b = (char)((*ptr << (1*8)) >> (3*8));
char c = (char)((*ptr << (2*8)) >> (3*8));
char d = (char)((*ptr << (3*8)) >> (3*8));
printf("0x%x\n", *ptr);
printf("0x%x\n", a);
printf("0x%x\n", b);
printf("0x%x\n", c);
printf("0x%x\n", d);
return 0;
}
输出:
0x40398917
0x40
0x39
0xffffff89
0x17
为什么我没有0x89
?
答案 0 :(得分:4)
这是因为您的char
变量已签名,并且在升级时会进行符号扩展(在这种情况下升级为更宽的类型)。签名扩展是一种在执行此促销时保留符号的方式,因此-119
保持为-119
,无论是8位,16位还是更宽的类型。
您可以通过显式使用unsigned char
来解决此问题,因为至少在C中,char
是有符号还是无符号是特定于实现的。来自C11 6.2.5 Types /15
:
实现应将char定义为与signed char或unsigned char具有相同的范围,表示和行为。
对于无符号类型,符号扩展不起作用,因为它们是......,好吧,无符号: - )
答案 1 :(得分:0)
char已签名 - 这意味着数字从-128到127运行。除此之外的任何数字都不适合。如果您将char
更改为unsigned char
,则会获得您期望的数字。
答案 2 :(得分:0)
memcpy
而不是演员char buff[4] = {0x17, 0x89, 0x39, 0x40};
unsigned int* ptr = (unsigned int*)buff;
这不正确:buff
未指向int对象或数组,因此未定义强制转换(unsigned int*)buff
。
将buff
重新解释为unsigned int
的安全方式是memcpy
:
char buff[4] = {0x17, 0x89, 0x39, 0x40};
unsigned int ui;
assert (sizeof ui == sizeof buff);
memcpy (buff, &ui, sizeof ui);
使用memcpy
时,您无法确定您复制的位代表是否对目标类型有效。
一种可移植但退化的方法是检查表示是否与现有对象匹配(注意,以下是愚蠢的代码):
char *null_ptr = 0;
char null_bytes[sizeof null_ptr] = {0};
if (memcmp (null_ptr, null_bytes, sizeof null_bytes)==0) {
char *ptr2;
memcpy (null_bytes, ptr2, sizeof null_bytes);
assert (ptr2 == 0);
}
此代码使用memcpy
并具有完全定义的行为(即使无用)。
int *ptr3 = (int*)null_bytes;
未定义,因为null_bytes
不是int
或unsigned int
的地址。