[英]Don't fully understand the output of very small C program using void*/char* to refer to and int + pointer arithmetic
我无法完全理解为什么以下代码片段的 output 在 onlinegdb.com 和 visual studio 上都是2
,而我预计会出现垃圾/崩溃值
我知道小端和大端是什么。 我的 comp 显然应该是 little endian,因为它是一个 32 位的英特尔核心双核。
我有 512,在 little endian 中是:
0000 0000 0010 0000 0000 0000 0000 0000
^ ^ ^
p p+1 p+2
p
将指向第一个0000
和p + 1
到0010
。 当我打印 2 来自0010
时,但是使用%d
它不应该打印0010 0000 0000 0000 0000 0000 xyzw rstu
的十进制表示(带有 8 个随机位)?
问:默认情况下,它是否将最后一位修补为 0,还是只是运气好,取 0 是因为它们使用了最后一个值? 它不应该是未定义的吗?
#include <stdio.h>
int main()
{
int x = 512;
void *p = &x;
printf("%d\n", *((char*)p + 1));
return 0;
}
对于
%d
,它不应该打印 0010 0000 0000 0000 0000 0000 xyzw rstu(8 个随机位)吗?
不,不是你的情况。
你这样做:
*((char*)p + 1)
这意味着以下内容:
p
并将其转换为char *
。char *
表示 1 个字节)。char *
),获得 1 个字节。printf
时,字节现在隐式转换为int
。换句话说,这就是发生的事情:
0000 0000 0100 0000 0000 0000 0000 0000
^^^^^^^^^
(char*)p+1
vvvvvvvvv
0100 0000 [0000 0000 0000 0000 0000 0000]
promotion to int when calling printf
所以这就是为什么您看不到“8 个随机位”的原因。
另一方面,如果您要做这样的事情:
// notice the second cast to (int*) AFTER advancing 1 byte
printf("%d\n", *(int*)((char*)p + 1));
那么这将是未定义的行为。 您可能已经看到了一些随机位(这意味着更大的值),或者您可能运气不好得到了零,但由于它是 UB,您不能真正期望从中得到任何有意义的东西。
我有 512,在小字节序中是:0000 0000 0010 0000 0000 0000 0000 0000
正确,除了它实际上是 0000 0000 0000 0010。Endianess 是字节顺序,而不是半字节顺序。
p+1 到 0010
正确,它指向字节0000 0010。
当我打印 2 来自 0010 时,但是使用 %d 它不应该打印 0010 0000...
不,因为当您取消引用 8 位char
时,您在 8 位临时 object 中以值 2 结束。
事实证明,诸如printf
类的可变参数函数将小的 integer 参数提升为int
(默认参数提升),而不管格式说明符如何。 因此,您最终得到一个值为2
的int
,然后printf
打印该值。
您可能希望在打印字节之前复制该字节:
int main()
{
const int x = 512;
uint8_t * p = (uint8_t *)(&x);
for (unsigned int i = 0u; i < sizeof(int); ++i)
{
const uint8_t value = *p++;
printf("%d\n", value);
}
return 0;
}
将 memory 复制到变量中可防止编译器将位置方程解释为 4 字节 integer(如您的示例所示)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.