C11标准effective type概念理解:代码分析验证及相关疑问
关于C11标准中Effective Type与Strict Aliasing的疑问解答
背景与标准规则摘录
本人在理解C11标准中的effective type和strict aliasing概念时存在困惑,目前对effective type有一定理解但仍有疑问。现将C11标准6.5p6中关于effective type的两条核心规则摘录如下:
- 若通过非字符类型左值向无声明类型的对象存储值,则该左值类型成为该对象本次及后续非修改访问的有效类型;
- 对无声明类型对象的所有其他访问,对象的有效类型即为访问所用左值的类型。
注:分配所得对象无声明类型。
本人认为“所有其他访问”仅指通过字符类型左值向无声明类型对象存储值的场景,并编写了两段代码进行分析:
- 第一段代码:先通过
unsigned char指针给malloc分配的对象赋值,再用signed char指针读取,认为此时对象有效类型变为signed char; - 第二段代码:先通过
unsigned int指针赋值,再用signed int指针读取,认为对象有效类型仍为unsigned int。
问题1:上述两段代码的分析是否正确?
你的分析是正确的,原因如下:
- 第一段代码:
unsigned char属于字符类型,存储操作触发规则2,该存储访问的有效类型为unsigned char;后续用signed char读取属于规则2的“其他访问”,因此本次读取的有效类型为访问所用的signed char类型。 - 第二段代码:
unsigned int是非字符类型,存储操作触发规则1,对象的有效类型被设置为unsigned int;后续用signed int读取属于“非修改访问”,因此沿用规则1设定的unsigned int作为有效类型。
问题2:体现两条规则差异的另一个示例
规则1场景(非字符类型存储+后续非修改访问)
#include <stdlib.h> int main() { void *buf = malloc(sizeof(double)); // 非字符类型左值存储,触发规则1,有效类型设为double double *d_ptr = buf; *d_ptr = 3.1415926; // 后续非修改访问,有效类型保持为double const double val = *(const double*)buf; }
此场景中,一旦通过非字符类型完成存储,后续所有非修改访问的有效类型固定为该存储类型,不受读取用左值类型影响。
规则2场景(字符类型存储+多类型读取)
#include <stdlib.h> int main() { void *buf = malloc(sizeof(int)); // 字符类型左值存储,触发规则2,本次存储的有效类型为unsigned char unsigned char *uc_ptr = buf; *uc_ptr = 0xFF; // 用signed char读取,有效类型为signed char signed char sc_val = *(signed char*)buf; // 用char读取,有效类型为char char c_val = *(char*)buf; }
此场景中,每次访问(无论存储还是读取)的有效类型都等于当前所用左值的类型,没有固定的后续有效类型。
问题3:“所有其他访问”包含的场景
除了你提到的通过字符类型左值存储的场景外,还包括:
- 对无声明类型对象的所有读取操作:只要不是规则1中“非字符类型存储后的非修改访问”,读取所用左值的类型即为有效类型;
- 非字符类型左值的修改存储操作:若已通过某非字符类型完成存储,之后再次用其他非字符类型左值修改存储对象,此时属于新的存储操作,会触发规则1的新实例,对象有效类型更新为新的左值类型;
- 跨类型的修改访问:比如用
float指针修改之前用int指针存储的无声明类型对象,此时有效类型会更新为float(规则1),属于“其他访问”范畴。
内容的提问来源于stack exchange,提问作者user24723440
相关产品推荐
相关产品推荐

