为啥我无法完成数组类型的 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,我们可以看到术语complete和incomplete的定义:
在翻译单元内的不同点,对象类型可能是不完整的(缺乏足够的信息来确定该类型对象的大小)或完整的(有足够的信息)。
因此,当我们谈论一个 类型 不完整时,我们实际上是在谈论 该类型的对象 的大小是不确定的。如果不声明该类型的对象,我们就不能谈论“不完整类型”。
在您的第一个示例中,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 对此非常清楚。我建议澄清 declaration 和 completion... 之间的区别
我们现在谈论的是void
,所以“我们不能谈论不完整的类型”显然是错误的。也许改写那句话,我不确定你想说什么。
评论不用于扩展讨论。此讨论变得 (1) 扩展和 (2) 无效。我已经把它清理干净了。除非他们添加新内容并且与问题相关。以上是关于为啥我无法完成数组类型的 typedef 名称?的主要内容,如果未能解决你的问题,请参考以下文章
如果我在 C 或 C++ 中执行 `typedef`,我啥时候应该在 typedef'ed 类型的末尾添加 `_t`? [复制]