我有这段代码:
int a;
char *x;
x = (char *) &a;
a = 512;
x[0] = 1;
x[1] = 2;
printf("%d\n");
return 0;
这将打印 513 。请说明,尤其是第3行。
答案 0 :(得分:5)
第3行仅将x
指向a
的地址。作为C语言中的一条特殊规则,允许我们专门使用字符指针来访问任何其他变量的各个字节。
对x
的进一步访问将更改a
的各个字节,其方式取决于CPU的字节性。在小字节序机器上,512 = 0x200,其中两个最低有效字节分别具有值0x00和0x02。 x[0] = 1;
将最低字节更改为0x01,x[1] = 2;
将值0x02写入已包含0x02的字节。结果将是0x201 = 513十进制。
这里的问题是printf("%d\n");
调用了未定义的行为,因为它包含错误数量的参数。
摘要:该代码是乱码,并且C语言未定义该程序将执行的操作。它可能会崩溃,打印任何值或根本不打印任何值。思考为什么它以某种方式表现是没有意义的实践。而是专注于学习如何避免未定义的行为错误。
答案 1 :(得分:1)
只要int大于特定机器上的char(并且必须为C标准),您的按字节访问本身就不会是未定义的。内在性可以确定。可以使用sizeof确定类型大小。
您实际上在这里所做的是将整数值设置为某些位模式(将代码中的x为char指针;数组符号[]允许您访问整数内的各个字节)。如果您再次访问作为整数的修改后的字节,则计算机的字节序将决定这些位模式代表什么。
只要您不写一个不属于原始整数的字节,该代码就不会出错,除了对printf的调用中缺少的参数是真正的UB。
剩下的问题是这种操纵可能会达到什么目的。但是这种技术也有用途。
答案 2 :(得分:0)
让我们假设您在一个int有4个字节的机器上。十六进制格式的512为'00 00 02 00'。在小字节序处理器上,指针指向最低有效字节。要分别设置每个字节,将指向int的指针强制转换为指向char的指针:x =(char *)&a;因为char总是以一个字节编码。现在,这四个字节被视为四个字节的数组。最低有效字节通过x [0] = 1设置为“ 1”;下一个字节设置为“ 2”(无论如何,因此行x [1] = 2;可以跳过),字节3和4保持不变为00和00。“ a”现在为“ 00 00 02 01”或513。 当然,在printf语句中缺少'a':printf(“%d \ n”,a);