有人可以向我解释在以下代码段的运行时间会发生什么,为什么会打印33? 谢谢,
#include <stdio.h>
void main(){
int* p = (int*)17;
printf("%d\n", (int)(long)(p+4));
}
答案 0 :(得分:6)
p
是指向int
或某些int
的指针。
您将其初始化为指向地址17.(由于几个原因,这是一个很大的问题,我们将会这样做。)
然后添加4。显然,您机器上的sizeof(int)
为4,即int
占用4个字节(32位)。当您向int
指针添加4时,编译器知道您希望将其指向4 int
值得更远,因此编译器会将4×4 = 16添加到该地址。现在p
指向地址33。
然后你从指向p
的指针“转换”(转换)long
。所以现在,而不是指向地址33的指针,它只是数字33。
然后再次将其从long
投射到int
。这基本上将它从33转换为33.(如果您的机器上的类型long
大于4个字节,则此转换可能涉及从64位值33转换为32位值33,也就是说,从0x0000000000000021
到0x00000021
。)
然后使用int
打印出最后%d
个值。所以你看到了数字33。
现在,通常,说
之类的话int* p = (int*)17;
是一个坏主意,因为你有一个指针,其值可能无法使用。通常,使用指针执行的一件事是操纵它们指向的值。但如果你要说
printf("value pointed to by p is %d\n", *p);
您最终会尝试从内存中的地址17获取int
值。但是(a)您可能无权从地址17读取,而(b)17不是4的倍数,因此您的处理器甚至可能不愿意尝试从那里获取int
如果你确实有权限。所以这段代码肯定会崩溃。
但是因为在你的代码中,你实际上从未尝试对int
假设的p
做任何事情(既不是在你加4之前也不是之后),你的代码可能会 - 而且几乎没有 - 似乎“工作”。
一方面,如果不是完全未定义的代码,这是不好的,不可移植的,几乎没有定义。但话说回来,它可能并不打算实用(显然没有人会用它来完成任何实际的工作)。因此,如果我们所有的内容都是指针运算如何工作的一个教训(特别是它如何根据指向对象的大小由编译器自动缩放),也许我们不必花费太多时间贬低它的许多丑闻和不完美之处。 (关于代码是 undefined 还是仅仅实现定义的,在评论主题中有一点点狡辩,但只要你注意不要编写代码像这样真实,你不一定要担心这种区别。)
如果你想学习更多或更少关于指针算术的课程,但是使用更合理且最便携的程序,试试这个:
#include <stdio.h>
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int main()
{
int *p = &a[3];
printf("p is %p and points to %d\n", p, *p);
printf("p+4 is %p and points to %d\n", p+4, *(p+4));
}
这里,我们不是将像17这样的人工值填充到p
中,而是将其初始化为指向实际数组,就像指针一样。而不是将指针值转换为int
并使用%d
打印它,我们使用%p
打印它,用于打印指针。
在我的机器上,此程序打印
p is 0x10f47a02c and points to 3
p+4 is 0x10f47a03c and points to 7
正如您所看到的,指针值不容易消化,如17和33这样的小数字,我的机器选择以十六进制打印它们。不过,很容易验证0x10f47a03c
- 0x10f47a02c
是0x10
还是16.我们添加了4,意思是“指出它现在指向的第4 int
点“,编译器增加了16。
[脚注。我说这是“大多数便携式”。为了使其完全可移植,您必须将printf
调用更改为
printf("p is %p and points to %d\n", (void *)p, *p);
printf("p+4 is %p and points to %d\n", (void *)(p+4), *(p+4));
严格地说,%p
仅定义为打印void
的通用指针,而不是任意其他指针类型。所以,严格来说,我们需要那些(void *)
强制转换,将指针值转换为正确的指针类型进行打印。]
答案 1 :(得分:1)
好吧,33
的结果告诉我你的机器使用int
sizeof(int) == 4
(4个字节)。
允许将整数转换为指针,并具有实现定义的结果。这就是这条线的作用:
int* p = (int*)17;
现在它是指向int的指针,p+4
将向指针添加int
大小的4倍。 17 + 4*4
为33
。
你的第二行
printf("%d\n", (int)(long)(p+4));
将此指针转换为long
,然后立即将其转换为int
。转换为long
在此无效。
所有这些的结果是实现定义,因为将在其他计算机上获得不同的结果。无法保证17
是指针的有效值,因此转换可以为您提供不同的值。
但假设17
是指针的有效值且计算机上的int
大小为4
,则结果为33
。