Jos*_*son -2 c pointers casting
任何人都可以向我解释在下面的代码片段的运行时期间发生了什么,为什么它打印33?谢谢,
#include <stdio.h>
void main(){
int* p = (int*)17;
printf("%d\n", (int)(long)(p+4));
}
Run Code Online (Sandbox Code Playgroud)
p是指向某个int或某个ints 的指针.
你初始化它指向地址17.(这是一个很大的问题,有几个原因,我们会得到.)
然后你添加4.显然,sizeof(int)在你的机器上是4,即int占用4个字节(32位).当你向int指针添加4时,编译器知道你想让它int更值得点4 ,所以编译器将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;
Run Code Online (Sandbox Code Playgroud)
是一个坏主意,因为你有一个指针,其值可能无法使用.通常,使用指针执行的一件事是操纵它们指向的值.但如果你要说
printf("value pointed to by p is %d\n", *p);
Run Code Online (Sandbox Code Playgroud)
你最终会尝试int从内存中的地址17 获取一个值.但是(a)你可能没有从地址17读取的权限,而(b)17不是4的倍数,所以int即使你有权限,你的处理器甚至可能不愿意尝试从那里取一个.所以这段代码肯定会崩溃.
但是因为在你的代码中,你实际上从来没有尝试用int假设指向的任何东西p(既不是在它之前也不是在它之后),你的代码可能 - 而且几乎没有 - 似乎"工作".
一方面,如果不是完全未定义的代码,这是不好的,不可移植的,几乎没有定义.但话说回来,它可能并不打算实用(显然没有人会用它来完成任何实际的工作).因此,如果我们所有的内容都是指针运算如何工作的一个教训(特别是它如何根据指向对象的大小由编译器自动缩放),也许我们不必花太多时间贬低它的许多丑闻和不完美之处.(关于代码是未定义还是仅仅是实现定义,在注释线程中有一点点狡辩,但只要你注意不要真正编写这样的代码,你不一定要担心区别.)
如果你想学习更多或更少关于指针算术的课程,但是使用更合理且最便携的程序,试试这个:
#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));
}
Run Code Online (Sandbox Code Playgroud)
在这里,p我们将初始化它指向一个实际的数组,而不是像17那样填充一个人工值.而不是将指针值转换为int并使用它打印%d,我们使用打印它来%p设计打印指针.
在我的机器上,这个程序打印出来
p is 0x10f47a02c and points to 3
p+4 is 0x10f47a03c and points to 7
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,指针值不容易消化,如17和33这样的小数字,我的机器选择以十六进制打印它们.然而,很容易验证0x10f47a03c- 0x10f47a02c是0x10,或16.我们添加了4,意思是" int让它指向现在指向的第4个过去",编译器增加了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));
Run Code Online (Sandbox Code Playgroud)
严格来说,%p只定义打印通用指针void,而不是任意其他指针类型.所以,严格来说,我们需要那些(void *)强制转换,将指针值转换为正确的指针类型进行打印.