C类型系统中兼容类型及顶层限定符忽略问题咨询
C类型系统里的“兼容类型”到底是什么?
哥们儿,我太懂你对着C标准抠兼容类型的痛苦了——这个概念的规则全散在各个章节里,确实容易晕。我帮你把这些内容串成清晰的逻辑:
核心底层规则
首先是标准里最基础的定义:
6.2.7 兼容类型和复合类型 1 若两种类型相同,则它们属于兼容类型;判断类型兼容性的额外规则分别在6.7.2(类型说明符)、6.7.3(类型限定符)及6.7.6章节中描述
简单说,相同类型一定是兼容类型——这是所有兼容性判断的起点。比如typedef int MyInt;定义的MyInt和int就是相同类型,自然兼容。
各章节的补充兼容性规则
接下来就是分散在不同章节的细节规则,我给你逐个拆解:
6.7.2 类型说明符:基本类型、枚举、结构体/联合体的规则
- 基本类型:比如
signed int和int是兼容的(只要你的编译器里int默认是带符号的,这几乎是所有实现的情况),但unsigned int和int绝对不兼容。另外,像long和long int也是兼容的,属于写法不同的同一类型。 - 枚举类型:两个枚举类型兼容的前提是:要么显式指定了相同的底层整数类型,要么编译器为它们选择了相同的默认底层类型。枚举数的名字和值不影响兼容性——哪怕两个枚举的枚举数完全不一样,只要底层类型兼容,它们就是兼容类型。
- 结构体/联合体:这部分要求最严格——只有当两个结构体/联合体的成员列表完全一致(包括成员的类型、名称、顺序,甚至填充对齐的细节),才是兼容类型。哪怕只是把两个成员的顺序调换,都会导致类型不兼容。
6.7.3 类型限定符:const/volatile不影响兼容性
类型限定符(const、volatile、restrict)不会改变类型的兼容性。比如int和const int是兼容类型,int*和const int*也是兼容类型。但要注意:兼容性不代表可以随意赋值——比如你不能把const int*直接赋值给int*,这是权限问题,不是类型兼容的问题。
6.7.6 声明符:指针、数组、函数的兼容规则
这部分是最容易踩坑的,也是日常写代码最常用到的:
- 指针类型:指向兼容类型的指针是兼容类型。比如
int*和MyInt*(上面typedef的)是兼容的,const int*和const MyInt*也是兼容的。但void*和其他对象指针(比如int*)是可以互相转换的,但它们本身不是兼容类型。 - 数组类型:数组兼容需要满足两个条件:一是元素类型兼容,二是数组的大小要么都明确指定且相等,要么都是不完整类型(比如
int[])。比如int[5]和int[5]兼容,int[]和int[]兼容,但int[5]和int[10]完全不兼容。 - 函数类型:函数类型兼容要求返回类型兼容,并且每个参数的类型都兼容,参数数量也要一致(旧式无参数列表的函数声明除外,不过现代C不建议用这种写法)。比如
int (*)(int)和int (*)(const int)是兼容的,因为int和const int兼容。
为什么要关心兼容类型?
搞懂这个概念的意义在于:
- 函数调用时,实参和形参的类型需要兼容(或者能隐式转换为兼容类型),否则会触发未定义行为;
- 使用
typedef重定义类型时,要确保新类型和原类型兼容,避免隐蔽的类型错误; - 联合体中,兼容类型的成员可以安全地互相访问(比如用
int成员存值,用unsigned int成员读取,只要它们兼容)。
内容的提问来源于stack exchange,提问作者Petr Skocik
相关产品推荐
相关产品推荐

