考虑指针时,它有助于绘制图表。指针是一个箭头,指向内存中的地址,带有指示值类型的标签。地址指示要看的地方,类型指示要取什么。投射指针会更改箭头上的标签,但不会更改箭头指向的位置。
d
inmain
是c
类型为的指针char
。Achar
是内存的一个字节,因此当d
取消引用时,您会在该内存的一个字节中获取值。在下图中,每个单元代表一个字节。
-+----+----+----+----+----+----+-
| | c | | | | |
-+----+----+----+----+----+----+-
^~~~
| char
d
当你施放d
到int*
,你是说d
真的指向一个int
值。在当今的大多数系统上,一个int
占用4个字节。
-+----+----+----+----+----+----+-
| | c | ?₁ | ?₂ | ?₃ | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
(int*)d
取消引用时(int*)d
,您将获得由这四个字节的内存确定的值。您获得的值取决于这些标记的单元格中的?
内容以及int
在内存中的表示方式。
甲PC是小端,这意味着,一个值int
被计算这种方式(假设它跨越4个字节):
* ((int*)d) == c + ?₁ * 2⁸ + ?₂ * 2¹⁶ + ?₃ * 2²⁴
。因此,如果您使用十六进制(printf("%x\n", *n)
),则最后两位始终是35
(即字符的值'5'
)。
其他一些系统是big-endian,并在另一个方向上排列字节:* ((int*)d) == c * 2²⁴ + ?₁ * 2¹⁶ + ?₂ * 2⁸ + ?₃
。在这些系统中,你会发现,价值总是开始与35
时十六进制打印。某些系统的大小int
不同于4个字节。很少有系统int
以不同的方式排列,但是您极不可能遇到它们。
根据您的编译器和操作系统的不同,您可能会发现每次运行该程序时该值都不相同,或者始终相同,但是在对源代码进行很小的调整时它就会更改。
在某些系统上,int
值必须存储在4(或2或8)倍数的地址中。这称为对齐要求。取决于地址是否c
正确对齐,程序可能会崩溃。
与您的程序相反,这是当您有一个int
值并指向它的指针时发生的情况。
int x = 42;
int *p = &x;
-+----+----+----+----+----+----+-
| | x | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
p
指针p
指向一个int
值。箭头上的标签正确描述了存储单元中的内容,因此取消引用时不会感到惊讶。