【问题标题】:Why can't I complete a typedef name of array type?为什么我无法完成数组类型的 typedef 名称?
【发布时间】:2017-06-30 22:31:26
【问题描述】:

C 标准规定(§6.2.5 p22):

未知大小的数组类型是不完整类型。完成了, 对于该类型的标识符,通过在稍后指定大小 声明(带有内部或外部链接)。

就变量声明而言,它工作正常:

int a[];
int a[2]; //OK

但是当我们在这些声明之前添加typedef 时,编译器会抱怨(我也更改了名称):

typedef int t[];
typedef int t[2]; //redefinition with different type

但是,当我们将 typedef 完成为不完整的结构时,它不会抱怨:

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];
}

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

【问题讨论】:

  • redefinition of typedef 的可能重复项。
  • 请限制您的编辑。我正在尝试写一个答案,我不想处理你的例子的重组。

标签: c arrays language-lawyer


【解决方案1】:

typedef int t[2]; 是不允许的,因为约束 6.7/3:

如果标识符没有链接,则在相同范围和相同名称空间中的标识符声明(在声明符或类型说明符中)不得超过一个,但以下情况除外:

  • 可以重新定义 typedef 名称以表示与当前相同的类型,前提是该类型不是可变修改的类型;

但是int[]int[2] 不是同一个类型,所以这个“例外”不适用,所以代码违反了约束。


关于你的第一句话:虽然 6.2.5/22 说可以完成不完整的类型,但这并不意味着任何尝试的完成都是自动合法的。尝试完成还必须符合语言的所有其他规则,在这种情况下,它不符合 6.7/3。

int a[]; int a[2]; 示例是可以的(在 6.7/3 下),因为 a 有链接;而在 typedef struct t t1; 中,struct t 在完成前后仍然是相同的类型。

【讨论】:

    【解决方案2】:

    6.2.5p1,我们可以看到术语completeincomplete的定义:

    在翻译单元内的不同点,对象类型可能是不完整的(缺乏足够的信息来确定该类型对象的大小)或完整的(有足够的信息)。

    因此,当我们谈论一个 类型 不完整时,我们实际上是在谈论 该类型的对象 的大小是不确定的。如果不声明该类型的对象,我们就不能谈论“不完整类型”。

    在您的第一个示例中,a 的大小是确定的,因为您已经使用第二个声明完成了对象的定义

    在您的第二个示例中,没有声明对象。一旦作出声明,例如t x = { 1, 2 };,很明显类型不是不完整的。

    在您的第三个示例中,您实际上并没有完成类型别名;您正在完成 struct 定义。你不妨这样写:

    typedef struct t t1;
    struct t { int m; };
    

    我们可以看到对struct标签重定义的进一步支持,以及6.7p3中VLA重定义的排除:

    如果标识符没有链接,则在相同范围和相同名称空间中的标识符声明(在声明符或类型说明符中)不得超过一个,除了:

    • 可以重新定义 typedef 名称以表示与当前相同的类型,前提是该类型不是可变修改的类型;
    • 标签可以按照 6.7.2.3 中的规定重新声明。

    【讨论】:

    • "我们不能在不声明该类型的对象的情况下谈论“不完整类型”。" - 也有函数参数,例如void f( int (*p)[] ); , *p 的类型不完整。 void 也是一个不完整的类型,你不能声明 void 对象。
    • @M.M "也有函数参数,例如void f( int (*p)[] );*p的类型不完整";我从未声称您不能声明具有不完整类型的对象。 "另外void 是一个不完整的类型,你不能声明void 的对象";同样,我从未声称您可以完成 void 类型。 6.2.5p19 对此非常清楚。我建议澄清 declarationcompletion... 之间的区别
    • 我们现在谈论的是void,所以“我们不能谈论不完整的类型”显然是错误的。也许改写那句话,我不确定你想说什么。
    • 评论不用于扩展讨论。此讨论变得 (1) 扩展和 (2) 无效。我已经把它清理干净了。除非他们添加新内容并且与问题相关。
    猜你喜欢
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    相关资源
    最近更新 更多