C语言数组指针场景下effective type(有效类型)判定规则相关疑问
C语言数组指针场景下的有效类型规则解答
核心问题的标准依据
C11/C17 标准第6.5节第6款明确规定了未声明类型内存(如malloc分配的内存)的有效类型规则:
对于没有声明类型的对象,其有效类型由对该存储进行写入操作的左值的类型决定。若通过某类型的左值读取未声明类型的存储,且此前没有通过其他类型的左值写入该存储,则该存储的有效类型临时为该左值的类型,直到下一次写入操作发生。
针对你提出的核心问题:通过数组指针访问单个数组成员时,仅会为被访问的对应内存设置有效类型,不会波及整个数组涵盖的全部内存。
你给出的示例中**foo = 123等价于(*foo)[0] = 123,这里用于写入的左值类型是int,因此只有起始地址到sizeof(int)字节的这部分内存的有效类型被设置为int,剩余9个int对应的内存仍然是无有效类型的状态,可以被其他类型的操作合法使用。
只有当你用整个数组类型的左值写入整块内存时,才会为整个数组范围的内存设置有效类型,例如:
int arr[10] = {0}; *foo = arr; // 这里左值*foo的类型是int[10],整块内存有效类型变为int[10]
实际场景代码的未定义行为判定
你给出的示例代码不会触发未定义行为,理由如下:
malloc返回的指针对齐满足所有基础类型的对齐要求,你计算的padded_int_size保证了bar的地址符合double的对齐要求,指针转换合法。- 操作
(*foo)[0]时仅修改了开头的int大小的内存,仅为这部分内存设置了int的有效类型,剩余的内存仍为无类型状态。 - 后续通过
bar访问double数组时,是第一次对对应内存执行写入操作,会将对应内存的有效类型设置为double,完全符合标准规定的有效类型规则,不存在类型别名违规。
注意:如果你后续通过(*foo)[1]~(*foo)[9]访问被bar使用的内存,才会触发类型别名相关的未定义行为。
聚合类型有效类型的争议补充
你提到的结构体场景的分歧确实存在:部分观点认为访问结构体第一个成员时会为整个结构体块设置有效类型,另一部分观点认为仅被访问的成员对应的内存会被设置有效类型。但数组场景的规则相对清晰,因为单个数组成员访问的左值类型明确为成员类型,没有隐含的整体聚合类型的赋值语义,因此不存在类似的歧义。
内容的提问来源于stack exchange,提问作者Jackson Allan
相关产品推荐
相关产品推荐

