繁体   English   中英

兼容类型并忽略C类型系统中的顶级限定符

[英]Compatible types and ignoring top-level qualifiers in the C type system

这是一个多部分的问题。

我一直在努力了解C型系统。 首先,C标准提到了“兼容类型”一词,所以我试图理解这一点。 这个定义似乎很分散,但我发现:

6.2.7兼容类型和复合类型1如果类型相同,则两种类型具有兼容类型。 确定两种类型是否兼容的附加规则在6.7.2中描述了类型说明符,在6.7.3中描述了类型限定符,在6.7.6中描述了声明符.55)此外,两个结构,联合或枚举类型在单独声明如果翻译单元的标签和成员满足以下要求,则它们是兼容的:如果使用标签声明一个,则另一个应使用相同的标签声明。 如果两者都在其各自的翻译单元内的任何地方完成,则以下附加要求适用:其成员之间应存在一对一的对应关系,以便每对相应的成员被宣布为兼容类型; 如果使用对齐说明符声明该对中的一个成员,则使用等效的对齐说明符声明另一个成员; 如果该对的一个成员使用名称声明,则另一个成员使用相同的名称声明。 对于两个结构,相应的成员应按相同的顺序声明。 对于两个结构或联合,相应的位域应具有相同的宽度。 对于两个枚举,相应的成员应具有相同的值。

REFS:
    6.7.2  short == short int == signed short == signed short int, etc.
    6.7.3
        10) For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.
    6.7.6
        1.2)
            For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
        2.6)
For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.

在我看来

  1. 如果它们的所有完整部分相同,则两种类型是相容的。
  2. (作为1的结果。)“完全兼容类型”实际上意味着“相同类型”。

首先,我想问一下我的解释是否准确。

其次,标准中的_Generic选择是根据“兼容类型”的概念定义的:

6.5.1.1通用选择2通用选择应具有不超过一个默认通用关联。 泛型关联中的类型名称应指定除可变修改类型之外的完整对象类型。 同一通用选择中的两个通用关联不应指定兼容类型。 通用选择的控制表达式应具有与其通用关联列表中命名的至多一种类型兼容的类型。 如果泛型选择没有默认的泛型关联,则其控制表达式的类型应与其通用关联列表中指定的类型之一完全兼容。

但编译器似乎对顶级限定符的解释不同:

$ $CC -x c -include stdio.h - <<<'int main(){puts( _Generic((int const){0}, int:"int", int const: "int const")); }' && ./a.out      #int with gcc, and int const with clang

在我看来,铿锵的解释是正确的,然而令人困惑的是

$ $CC -x c -include stdio.h - <<<'int main(){puts( _Generic((int const)0, int:"int", int const: "int const")); }' && ./a.out        

甚至在铿锵声中说"int"

因此,我的第二个问题是在标准会是什么解释的基础(int const)0类型的int(int const){0}类型的int const

最后,在我的所有编译器(tcc,gcc,clang)中,在确定fucntions或函数指针之间的兼容性时,顶级限定符似乎在原型类型列表中的所有类型上被忽略:

for CC in tcc gcc clang; do echo CC=$CC; $CC -x c  - <<<'int main(){ static void (*f)(int*), (*g)(int * restrict const volatile);  f=g; }' ; done #no complaints

但我在标准中找不到任何提及,所以我的最后一个问题是:

在确定函数兼容性的上下文中,是否忽略原型类型列表中的顶级限定符列出了标准语言?

谢谢。

事情稍微复杂一些,因为_Generic()有一些额外的规则,因为你似乎遇到了一个现已修复的clang中的错误。

C18(6.5.1.1第2段)为通用选择增加了一些要求:

控制表达式的类型是表达式的类型,就好像它经历了左值转换,93)数组到指针转换,或函数到指针转换。

脚注93指出:

左值转换会丢弃类型限定符。

对于_Generic((int const){0}, ...)示例,FreeBSD clang版本6.0.1报告int

基本上,由于控制表达式的左值转换,泛型选择不是探索兼容类型概念的非常好的方式,因为它与类型限定符有关。

兼容类型并不意味着它们必须与所有用途完全相同 注意

struct foo *

在一个翻译单元兼容

struct foo *

如果两者都不是指向完整类型的指针。 但是,如果foo的成员甚至在声明之后定义,那么定义必须匹配,否则先前的指针将不兼容!

同样,类型及其typedef彼此兼容。

但兼容性并不要求类型相同:数组可以具有不完整和完整类型,并且它们彼此兼容。 在一个翻译单元中,您可以声明

extern int a[];

在另一个

int a[10];

它们是兼​​容的类型。

C11 6.7.6p6

要使两个数组类型兼容,两者都应具有兼容的元素类型,如果两个大小说明符都存在,并且是整数常量表达式,则两个大小说明符应具有相同的常量值 如果在要求它们兼容的上下文中使用这两种数组类型,则如果两个大小说明符计算为不相等的值,则它是未定义的行为。

此外,VLA类型可以是具有静态维度数组的兼容类型 - 如果元素类型相同,则它被视为始终兼容,但如果维度在需要时实际上不匹配,则行为将是不确定的。


至于_Generic ,Clang绝对是错的。 事实上,这已在缺陷报告481中得到解决,并且认为Clang始终是错误的并且GCC是对的; ov2k所述,该标准针对C18进行了修正。 另请参阅此Q / A的另一种情况,这次是因为Clang没有将数组的左值转换为指针类型。

(const int){0}确实创建了一个类型为const int (复合文字)的左值,但后续的左值转换应该删除类型限定符,结果应该是int 实际上_Generic选择不应该能够选择任何const限定的类型,所以我认为编译器应该发出一个警告,即使在那里有const限定符

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM