如何解决不能完全理解使用void * / char *引用和int +指针算法的非常小的C程序的输出
我无法完全理解为什么当我期望垃圾值/崩溃值时,onlinegdb.com和Visual Studio上的以下代码段的输出为2
我知道小端和大端是什么。我的comp很明显应该是低位字节序,因为它是32位Intel Core Duo。
我有512个,在小尾数法中是:
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个随机位)吗?
Q:是默认将最后一位修补为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 *
。 - 前进1个位置(广播到
char *
表示1个字节)。 - 取消引用(仍为
char *
),获取1个字节。 - 您获得的字节为2。
- 现在,该字节在传递给
int
时隐式转换为printf
。
换句话说,就是这样:
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 00000010。字节序为 byte 字节,而不是半字节顺序。
p +1到0010
正确,它指向 byte 0000 0010。
当我打印2时是从0010开始的,但是使用%d时它应该不会打印0010 0000 ...
否,因为当取消引用8位char
时,您会在8位临时对象中以值2结尾。
事实证明,诸如printf
之类的可变参数函数都将小整数参数提升为int
(默认参数提升),而与格式说明符无关。因此,最后得到一个int
,其值为2
,然后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;
}
将内存的副本制作为变量可防止编译器将位置方程解释为4字节整数(如您的示例)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。