C标准规定(§6.2.5p22):
未知大小的数组类型是不完整类型。它完成了, 对于该类型的标识符,通过在稍后指定大小 声明(内部或外部联系)。
就变量声明而言,它的工作正常:
typedef
但是当我们在这些声明之前添加typedef int t[];
typedef int t[2]; //redefinition with different type
时,编译器会抱怨(我也更改了名称):
typedef struct t t1;
typedef struct t { int m; } t1; //OK
但是当我们完成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];
}
数组的不完整typedef的可能用例可能是这样的:
setStats()
在上面的例子中,我想声明一个指向结构内部数组的指针,其中元素的数量等于结构大小。是的我可以使用结构而不是数组,但为什么我可以在上述选项可能的情况下使用?
答案 0 :(得分:4)
typedef int t[2];
如果标识符没有链接,则标识符的声明(在声明符或类型说明符中)不得超过一个具有相同作用域和相同名称空间的声明,除了:
- 如果类型不是可变修改类型,则可以重新定义typedef名称以表示与其当前相同的类型;
但是int[]
和int[2]
不是同一类型,因此“except”不适用,因此代码违反了约束。
关于你的第一个引用:虽然6.2.5 / 22表示可以完成一个不完整的类型,但并不意味着任何尝试完成都是自动合法的。尝试完成还必须符合该语言的所有其他规则,在这种情况下,它不符合6.7 / 3.
int a[]; int a[2];
示例正常(在6.7 / 3下),因为a
具有链接;在typedef struct t t1;
中,struct t
在完成之前和之后仍然是同一类型。
答案 1 :(得分:0)
从6.2.5p1开始,我们可以看到术语完整和不完整的定义:
在翻译单元内的各个点,对象类型可能不完整(缺少足够的信息来确定该类型对象的大小)或完整(具有足够的信息)。
因此,当我们谈论类型不完整时,我们真的在谈论对象的大小是不确定的。如果不声明那种类型的对象,我们就不能谈论“不完整的类型”。
在您的第一个示例中,a
的大小是确定的,因为您已使用第二个声明完成了对象的定义。
在第二个示例中,没有声明对象。一旦声明,例如, t x = { 1, 2 };
,很明显类型不完整。
在你的第三个例子中,你实际上并没有完成类型别名;您正在完成struct
定义。你可能也写过:
typedef struct t t1;
struct t { int m; };
我们可以看到对struct
标签重新定义的进一步支持,以及6.7p3中对VLA重新定义的排除:
如果标识符没有链接,则标识符的声明(在声明符或类型说明符中)不得超过一个具有相同作用域和相同名称空间的声明,除了:
- 如果类型不是可变修改类型,则可以重新定义typedef名称以表示与其当前相同的类型;
- 标签可以按照6.7.2.3中的规定重新申报。