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

这是一个多部分的问题。

我一直在努力了解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通用选择应具有不超过一个默认通用关联。 generics关联中的类型名称应指定除可变修改类型之外的完整对象类型。 同一通用选择中的两个通用关联不应指定兼容类型。 通用选择的控制表达式应具有与其通用关联列表中命名的最多一种类型兼容的类型。 如果generics选择没有默认的generics关联,则其控制表达式的类型应与其通用关联列表中指定的类型之一完全兼容。

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

 $ $CC -xc -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 -xc -include stdio.h - <<<'int main(){puts( _Generic((int const)0, int:"int", int const: "int const")); }' && ./a.out 

即使在铿锵声中也说"int"

所以我的第二个问题是,从(int const)0类型开始,解释(int const)0的类型为int(int const){0}是什么?

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

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

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

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

谢谢。

1. (const int){0}

我也认为铿锵是正确的; 它的类型与(int){0} 。 见下文。

2. (const int)0

首先,请注意:

与限定类型关联的属性仅对作为左值的表达式有意义。 (§6.7.3(类型限定词)/第4段)

演员的结果不是左值,如§6.5.4的注释104(演员)所示:

演员阵容不会产生左值。 因此,对合格类型的强制转换与对该类型的非限定版本的强制转换具有相同的效果。

脚注不具有约束力,但是这个脚注源于这样一个事实: 转换运算符不在左值转换的exception列表中(参见§6.3.2.1),因此强制转换会导致左值转换 ,结果是删除了限定符:

没有数组类型的左值被转换为存储在指定对象中的值(并且不再是左值); 这称为左值转换。 如果左值具有限定类型,则该值具有左值类型的非限定版本; 另外,如果左值具有primefaces类型,则该值具有左值类型的非primefaces版本; 否则,该值具有左值的类型。 (§6.3.2.1(左值,数组和函数指示符)/第2段)

与第一种情况的区别非常明显。 第一种情况是复合文字,而不是强制转换,并且:

…(当类型名称指定对象类型时),复合文字的类型是由类型名称指定的类型。 ……结果是左值。 (§6.5.2.5(复合文字)/第4段)

由于复合文字是左值,它应该保留其const限定符,这意味着第一个例子中gcc是错误的。

3.合格的function参数和类型兼容性

参见§6.7.6.3(函数声明符)/第15段的最后一句:

在确定类型兼容性和复合类型时,使用函数或数组类型声明的每个参数都被视为具有调整类型,并且使用限定类型声明的每个参数都被视为具有其声明类型的非限定版本。