为什么我不能完成数组类型的typedef名称?

时间:2017-02-13 02:02:56

标签: c arrays language-lawyer

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()

在上面的例子中,我想声明一个指向结构内部数组的指针,其中元素的数量等于结构大小。是的我可以使用结构而不是数组,但为什么我可以在上述选项可能的情况下使用?

2 个答案:

答案 0 :(得分:4)

由于约束条件6.7 / 3:

,因此不允许

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中的规定重新申报。
  •