[英]typecasting a pointer to an int .
我无法理解该程序的输出。 我得到的是,首先,指针p,q,r和s指向null。
然后,有一个类型转换。 但是输出如何达到1 4 4 8呢? 我的想法可能错了。 所以,如果我错了,请纠正我。
int main()
{
int a, b, c, d;
char* p = (char*)0;
int *q = (int *)0;
float* r = (float*)0;
double* s = (double*)0;
a = (int)(p + 1);
b = (int)(q + 1);
c = (int)(r + 1);
d = (int)(s + 1);
printf("%d %d %d %d\n", a, b, c, d);
_getch();
return 0;
}
指针算术,在这种情况下,将整数值添加到指针值,以其指向的类型为单位提高指针值。 如果您有一个指向8字节类型的指针,则在该指针上加1将使该指针前进8个字节。
指针算术仅在原始指针和加法结果都指向同一数组对象的元素时才有效,或者恰好在其末尾。
C标准描述的方式是( N1570 6.5.6第8段):
将具有整数类型的表达式添加到指针或从指针中减去时,结果将具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式。
[...]
如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素之后,则求值不应产生溢出; 否则,行为是不确定的。 如果结果指向数组对象的最后一个元素之后,则不应将其用作被评估的一元*
运算符的操作数。
数组末尾的指针是有效的,但是您不能取消引用它。 单个非数组对象被视为1元素数组。
您的程序具有未定义的行为。 您将1
添加到一个空指针。 由于空指针没有指向任何对象,因此它的指针算术是不确定的。
但是不需要编译器检测未定义的行为,您的程序可能会像对待任何有效指针值一样对待空指针,并以相同的方式对其执行算术运算。 因此,如果null指针指向地址0
(虽然不能保证,顺便说一句,但这很常见),那么将其添加1
可能会给您一个指向地址N的指针,其中N是它所指向类型的字节大小至。
然后,您将结果指针转换为int
(最多由实现定义),如果指针大于int
,则将丢失信息,并且可能会产生陷阱表示形式 ),然后打印int
值。 在大多数系统上,结果可能会向您显示char
, int
, float
和double
的大小,通常分别为1、4、4和8个字节。
程序的行为是不确定的,但是它在系统上的实际行为是典型且毫不奇怪的。
这是一个没有未定义行为的程序, 它说明了同一点:
#include <stdio.h>
int main(void) {
char c;
int i;
float f;
double d;
char *p = &c;
int *q = &i;
float *r = &f;
double *s = &d;
printf("char: %p --> %p\n", (void*)p, (void*)(p + 1));
printf("int: %p --> %p\n", (void*)q, (void*)(q + 1));
printf("float: %p --> %p\n", (void*)r, (void*)(r + 1));
printf("double: %p --> %p\n", (void*)s, (void*)(s + 1));
return 0;
}
和我的系统上的输出:
char: 0x7fffa67dc84f --> 0x7fffa67dc850
int: 0x7fffa67dc850 --> 0x7fffa67dc854
float: 0x7fffa67dc854 --> 0x7fffa67dc858
double: 0x7fffa67dc858 --> 0x7fffa67dc860
输出的结果不如程序的输出清晰,但是如果仔细检查结果,您会发现在char*
上加1会使它前进1个字节,将int*
或float*
提前4个字节,将double*
提前8个字节字节。 (除char
,根据定义, char
的大小为1个字节,在某些系统上可能有所不同。)
请注意, "%p"
格式的输出是实现定义的,并且可能反映也可能不会反映您可能期望的算术关系。 我在系统(Cray向量计算机)上工作,其中增加char*
指针实际上会更新存储在64位字的高3位中的字节偏移量。 在这样的系统上,除非您了解机器和编译器如何工作的底层细节,否则我的程序输出(以及您的程序输出)将更加难以解释。
但是对于大多数目的,您不需要了解那些底层细节。 重要的是指针算术按照C标准中的描述进行工作。 了解比特级的实现方式对于调试很有用(这几乎就是%p
的用途),但对于编写正确的代码则不是必需的。
向指针加1会将指针前进到适合该指针类型的下一个地址。
当将(null)pointers + 1重铸为int时,您实际上在打印指针所指向的每种类型的大小。
printf("%d %d %d %d\n", sizeof(char), sizeof(int), sizeof(float), sizeof(double) );
做几乎相同的事情。 如果只想将每个指针增加1个BYTE ,则需要在将它们递增之前将它们强制转换为(char *)以使编译器知道
搜索有关指针算法的信息以了解更多信息。
您正在将指针类型转换为原始数据类型,而不是将类型强制转换为指针本身,然后使用*
(间接)运算符间接指向该变量值。 例如, (int)(p + 1);
均值p
; 在这种情况下,指向常量的指针首先递增到内存( 0x1
)中的下一个地址。 然后将这个0x1
类型转换为int
。 这完全有道理。
您获得的输出与每种相关类型的大小有关。 像这样进行指针算术运算时,它将指针值增加的值乘以基本类型的大小。 发生这种情况是为了促进正确的阵列访问。
因为在计算机上char
, int
, float
和double
的大小分别为char
和8,所以当您向每个关联的指针加1时,它们的大小就会反映出来。
编辑:
删除了我认为没有表现出未定义行为的替代代码,实际上确实如此。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.