基本 C 不支持将任何指针类型转换为任何其他指针类型(即,没有 C 标准不需要的任何扩展或行为的 C)。 2018 C 标准在第 6.3.2.3 条第 7 段中说:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未正确对齐引用的类型,则行为未定义。否则,当再次转换回来时,结果将等于原始指针......
在那篇文章中,我们看到了两个限制:
- 如果指针未正确对齐,转换可能会以各种方式失败。在您的示例中,将
int * 转换为short * 不太可能失败,因为int 通常比short 具有更严格的对齐方式。但是,基本 C 不支持反向转换。假设您使用short x[20]; 或char x[20]; 定义了一个数组。然后数组将根据short 或char 的需要对齐,但不一定根据int 的需要对齐,在这种情况下(int *) x 的行为不会由C 标准定义。
- 转换产生的值大多未指定。这段话只保证将它转换回来会产生原始指针(或等效的东西)。它不能保证您可以在不将其转换回来的情况下对指针执行任何有用的操作——您不一定要使用从
int * 转换而来的指针来访问 short。
该标准确实对某些指针转换做出了一些额外的保证。其中之一是上述段落的延续:
… 当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。结果的连续递增,直到对象的大小,产生指向对象剩余字节的指针。
因此,您可以使用从int * 转换而来的指针来访问表示int 的各个字节,并且您可以执行相同的操作来访问任何其他对象类型的字节。但这种保证仅适用于访问具有字符类型的单个字节,而不是 short 类型。
从上面我们知道,在你的例子中short * c = (short *)y;之后,y不一定指向它源自的x的任何部分——指针转换产生的值不能保证有效作为short *。但是,即使它确实指向 x 所在的位置,base C 也不支持使用 c 访问这些字节,因为 6.5 7 说:
对象的存储值只能由具有以下类型之一的左值表达式访问:
——与对象的有效类型兼容的类型,
——与对象的有效类型兼容的类型的限定版本,
——对象的有效类型对应的有符号或无符号类型,
— 有符号或无符号类型,对应于对象有效类型的限定版本,
——在其成员中包含上述类型之一的聚合或联合类型(递归地,包括子聚合或包含联合的成员),或
——一种字符类型。
因此,C 不支持您的示例中的 *c = 0;,原因有两个:c 不一定指向 x 的任何部分或任何有效地址,即使是这样, C 标准未定义使用 short 类型修改 int x 的一部分。它可能在您的 C 实现中工作,甚至可能由您的 C 实现支持,但它不是严格符合 C 代码。
C 标准提供了void * 类型,以便在特定类型不适用时使用。 6.3.2.3 1 对指向void 的指针做出与对指向对象的指针类似的保证:
指向void 的指针可以转换为或从指向任何对象类型的指针转换。指向任何对象类型的指针可以转换为指向void 的指针并再次返回;结果应与原始指针比较。
void * 用于必须处理任意对象类型的例程,例如qsort。 char * 可以达到这个目的,但最好有一个单独的类型,清楚地表明没有特定类型与之关联。例如,如果函数的参数是char *p,则该函数可能会无意中使用*p 并获得它不想要的字符。如果参数为void *p,则函数必须将指针转换为特定类型,然后才能使用它来访问对象。因此,为“通用指针”设置一个特殊类型可以帮助避免错误,并向阅读代码的人表明意图。