如本例所示:
#include <stdio.h>
void foo(int (*p)[5])
{
int *i = (int *)p;
printf("%d\n", *i);
}
定义了吗?IMO它不是.
问题启发this question
请记住,这个问题是100
如本例所示:
#include <stdio.h>
void foo(int (*p)[5])
{
int *i = (int *)p;
printf("%d\n", *i);
}
定义了吗?IMO它不是.
问题启发this question
请记住,这个问题是100
C 2018标准中没有任何定义,因此行为是未定义的(4 2:"未定义的行为在本文中以"未定义的行为"或省略任何明确的行为定义来表示.
转换执行转换(6.5.4 5).转换在6.3中详细说明.指针转换在6.3.2.3中规定.第1段涵盖指向或指向void *
的指针,但此处并非如此.第2款涵盖同一类型不同限定版本之间的转换,但此处并非如此.第3段介绍了空指针常量的转换,这里不是这样的.第4段涉及空指针的转换,这里不是这样.第5段介绍了整数到指针的转换,这里不是这样的.第6段涉及到整数的转换,这里不是这样.第8段介绍了指针到函数类型的转换,这里不是这样的.
现在只剩下第7段:
指向对象类型的指针可以转换为指向不同对象类型的指针.如果结果指针与引用的类型没有正确对齐,则行为是未定义的.否则,当再次转换回时,结果应与原始指针比较.当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低地址字节.结果的连续增量(直到对象的大小)产生指向对象剩余字节的指针.
这也适用于我们的情况,but it does not tell us what the value of the result is.它告诉我们,当我们将结果转换回原始类型时,我们将有一个与原始指针等效的值.但是可以想象,转换后的值是某种编码形式的,不适合用于解引用.
例如,设想一个为调试而设计的C版本,其中所有指针都用起源信息进行检测.指向int [2]
的指针可能是16个字节,其中4个字节包含地址,12个字节包含该地址作为类型int [2]
的指针的信息.将其转换为int *
可能会产生一个具有完全相同字节的指针,而将其转换回将产生相同字节.由于这是C的调试实现,所以每次指针被解除引用时,它都会判断存储在这些字节中的指针出处.当我们使用*p
时,它看到字节表示指针起源于指向int [2]
的指针,而p
就是该类型,所以它允许取消引用,程序继续.
然而,当我们使用*i
时,它看到字节表示指针起源于指向int [2]
的指针,但i
是int *
,所以它打印一条错误消息并停止程序.
这个假设的程序符合C标准:
int *
没有指定工作,它不工作,所以这符合标准.进一步注意,标准中指定了将指针转换为指向字符类型的指针并使用它来访问表示对象的字节,但我们假设的C实现可以允许这样做.它只是批准使用任何指向对象的指针类型来访问字符左值,即使出处说它起源于其他类型.
人们可能认为标准的intention是允许转换后的指针用作指向它们新类型的指针,但it does not explicitly say that.因此,从技术上讲,这种行为并不是由C标准定义的.