为什么这样有效:
int a = 5;
int *aPtr = &a;
printf("%i", *aPtr);
但这不是:
int a = 5;
int aPtr = &a;
printf("%i", *aPtr);
我不是在寻找它引发的错误。我试图了解为什么这从概念上讲是行不通的。
最佳答案
int aPtr = &a;
声明一个类型为aPtr
的名为int
的对象,因此它不是指针。
更糟糕的是,在几个常用平台上(例如,Windows XP之后的所有x64版本的Windows),使用sizeof(int) != sizeof(int *)
,因此您将丢失指针包含的某些信息,可能会使存储的值无用。
假定它起作用,但是aPtr
仍然是int
类型的对象,因此您不能使用指针间接获取存储在aPtr
地址中的值,这意味着表达式*aPtr
将不会编译。没有什么可以阻止您将aPtr
强制转换为正确的指针类型:
int a = 5;
int aPtr = &a;
printf("%i", *(int *)aPtr);
同样,这是假定
aPtr
存储a
的完整地址。无论如何,这只是C的类型安全,这是一件好事(请参见上面的sizeof(int) != sizeof(int *)
段落)。如果用“概念上”的意思是“假定地址正确存储在
aPtr
中”,那么代码就没有什么问题,除了上面的强制转换示例所示,它不是有效的C。如果地址是0x80,则您甚至可以将其存储在一个小的unsigned char
对象中。它被存储在内存中的该地址,无论C阻止您通过编译语法上无效的代码来阻止您执行此操作。当然,仅使用适当的变量类型要容易得多,而不是与编译器进行强制转换。再一次,您可能会问:“如果
&a
存储在aPtr
中,为什么编译器不能识别出并仅仅理解*aPtr
与*&a
相同?”如果这是问题,那么答案很简单:将&a
存储在类型为T
的对象中后,编译器就会知道该对象用于存储类型为T
的值,仅此而已。无论您是否在该对象中存储一个内存,它都不知道它包含一个内存地址。它只知道里面存储着一个T
类型的值。同样,这只是C的类型系统按预期工作。