任何人都可以向我解释以下内容

时间:2018-05-04 18:33:32

标签: c pointers casting

有人可以向我解释在以下代码段的运行时间会发生什么,为什么会打印33? 谢谢,

#include <stdio.h>

void main(){
    int* p = (int*)17;
    printf("%d\n", (int)(long)(p+4));
}

2 个答案:

答案 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,也就是说,从0x00000000000000210x00000021。)

然后使用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 - 0x10f47a02c0x10还是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*433

你的第二行

printf("%d\n", (int)(long)(p+4));

将此指针转换为long,然后立即将其转换为int。转换为long在此无效。

所有这些的结果是实现定义,因为在其他计算机上获得不同的结果。无法保证17是指针的有效值,因此转换可以为您提供不同的值。

但假设17是指针的有效值且计算机上的int大小为4,则结果为33