为啥我无法完成数组类型的 typedef 名称?

Posted

技术标签:

【中文标题】为啥我无法完成数组类型的 typedef 名称?【英文标题】: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 的可能重复项。 请限制您的编辑。我正在尝试写一个答案,我不想处理你的例子的重组。 【参考方案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) 无效。我已经把它清理干净了。除非他们添加新内容并且与问题相关。

以上是关于为啥我无法完成数组类型的 typedef 名称?的主要内容,如果未能解决你的问题,请参考以下文章

typedef用法

C语言中的typedef是啥意思啊

为啥 C 程序员使用 typedef 来重命名基本类型?

如果我在 C 或 C++ 中执行 `typedef`,我啥时候应该在 typedef'ed 类型的末尾添加 `_t`? [复制]

无法通过引用传递typedef结构

为啥 C# 数组对 Enumeration 使用引用类型,而 List<T> 使用可变结构?