AnA*_*ons 9 c arrays language-lawyer
C标准规定(§6.2.5p22):
未知大小的数组类型是不完整类型.对于该类型的标识符,通过在稍后的声明中指定大小(具有内部或外部链接)来完成.
就变量声明而言,它工作得很好:
int a[];
int a[2]; //OK
Run Code Online (Sandbox Code Playgroud)
但是当我们typedef在这些声明之前添加时,编译器会抱怨(我也更改了名称):
typedef int t[];
typedef int t[2]; //redefinition with different type
Run Code Online (Sandbox Code Playgroud)
但是,当我们完成typedef到不完整的结构时,它不会抱怨:
typedef struct t t1;
typedef struct t { int m; } t1; //OK
Run Code Online (Sandbox Code Playgroud)
数组的不完整typedef的可能用例可能是这样的:
int main(int n, char **pp)
{
typedef int t1[][200];
typedef struct t { t1 *m; int m1; } t0;
typedef int t1[sizeof (t0)][200];
}
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我想声明一个指向结构内部数组的指针,其中元素的数量等于结构大小.是的我可以使用结构而不是数组,但为什么我可以在上述选项可能的情况下使用?
从6.2.5p1 ,我们可以看到术语完整和不完整的定义:
在翻译单元内的各个点,对象类型可能是不完整的(缺乏足够的信息来确定该类型的对象的大小)或完整的(具有足够的信息)。
因此,当我们谈论不完整的类型时,我们实际上是在谈论该类型的对象的大小是不确定的。如果不声明该类型的对象,我们就不能谈论“不完整类型”。
在第一个示例中, 的大小是确定的,因为您已经使用第二个声明完成了对象的a定义。
在第二个示例中,没有对对象进行声明。一旦做出声明,例如t x = { 1, 2 };,很明显该类型并非不完整。
在第三个示例中,您实际上并未完成类型别名;而是完成了类型别名。你正在完成struct定义。你不妨这样写:
typedef struct t t1;
struct t { int m; };
Run Code Online (Sandbox Code Playgroud)
我们可以看到对标签重新定义的进一步支持,并在6.7p3struct中排除了 VLA 重新定义:
如果标识符没有链接,则在相同范围和相同名称空间中不应有超过一个标识符声明(在声明符或类型说明符中),但以下情况除外:
- typedef 名称可以被重新定义以表示与当前相同的类型,前提是该类型不是可变修改类型;
- 标签可以按照 6.7.2.3 中的规定重新声明。