我想了解真正需要一个空指针,例如在下面的代码中,我使用强制转换来能够以不同的方式使用相同的 ptr,那么如果可以强制转换,为什么真的有一个空指针?
int main()
{
int x = 0xAABBCCDD;
int * y = &x;
short * c = (short *)y;
char * d = (char*)y;
*c = 0;
printf("x is %x\n",x);//aabb0000
d +=2;
*d = 0;
printf("x is %x\n",x);//aa000000
return 0;
}
Run Code Online (Sandbox Code Playgroud)
基 C 不支持将任何指针类型转换为任何其他指针类型(即,C 没有任何扩展或 C 标准不需要的行为)。2018 C 标准在第 6.3.2.3 条第 7 段中说:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未针对引用类型正确对齐,则行为未定义。否则,当再次转换回来时,结果将与原始指针相等......
在那段经文中,我们看到了两个限制:
int *为 ashort *不太可能失败,因为int通常比short. 但是,基本 C 不支持反向转换。假设您使用short x[20];或定义了一个数组char x[20];。然后数组将根据 ashort或 的需要对齐char,但不一定根据a 的需要对齐int,在这种情况下(int *) x, C 标准不会定义的行为。int *来访问short.该标准确实对某些指针转换做出了一些额外的保证。其中之一是以上段落的延续:
... 当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低地址字节。结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。
因此,您可以使用转换为 from 的指针int *来访问代表 an 的各个字节int,并且您可以使用相同的方法访问任何其他对象类型的字节。但该保证仅适用于访问具有字符类型的单个字节,而不适用于short类型。
从上面我们知道,short * c = (short *)y;在你的例子中之后,y不一定指向x它起源的任何部分——指针转换产生的值根本不能保证作为 a 工作short *。但是,即使它确实指向了位置x,基础 C 也不支持使用c访问这些字节,因为 6.5 7 说:
对象的存储值只能由具有以下类型之一的左值表达式访问:
— 与对象的有效类型兼容的类型,
— 与对象的有效类型兼容的类型的限定版本,
— 对应于对象有效类型的有符号或无符号类型,
— 一种类型,它是与对象有效类型的限定版本相对应的有符号或无符号类型,
— 在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含联合的成员),或
— 一种字符类型。
所以,*c = 0;在你的例子不是由下两个原因支持:c并不一定指向的任何部分x或任何有效的地址,而且,即使是这样,修改的部分的行为int x使用short类型不是由C定义标准。它可能看起来适用于您的 C 实现,甚至可能受您的 C 实现支持,但它并不严格符合 C 代码。
C 标准提供了void *在特定类型不合适时使用的类型。6.3.2.3 1void为指向对象的指针提供了类似的保证:
指向的指针
void可以与指向任何对象类型的指针相互转换。指向任何对象类型的指针都可以转换为指向void和返回的指针;结果应与原始指针相等。
void *与必须使用任意对象类型的例程一起使用,例如qsort. char *可以用于此目的,但最好有一个单独的类型,明确表示没有特定类型与之关联。例如,如果函数的参数是char *p,则该函数可能会无意中使用*p并获取它不想要的字符。如果参数是void *p,则函数必须在使用指针访问对象之前将指针转换为特定类型。因此,为“通用指针”使用特殊类型可以帮助避免错误以及向阅读代码的人表明意图。