UB是否在不同的编译单元中将相同的数组声明为具有不同大小的extern

Ser*_*sta 4 c linker language-lawyer

这主要是应该定义和声明匹配的后续行动

在C中合法(例如)int a[10];在一个编译单元和extern int a[4];另一个编译单元中是否合法?

(您可以在我的回答问题中找到一个工作示例)


免责声明:

  • 我知道它很危险,不会在生产代码中执行
  • 我知道如果你们在同一个编译单元中(通常通过在包含定义的文件中包含.h)编译器检测到错误
  • 我已经阅读了Jonathan Leffler 关于如何使用extern在源文件之间共享变量的优秀答案但是在那里找不到这个特定点的答案 - 即使乔纳森表现出更糟糕的用法......

即使引用帖子中的不同评论发现作为UB,我也找不到任何权威参考.所以我会说这里没有UB,第二个编译单元可以访问数组的开头,但我真的想要一个确认 - 或者说是为什么它是UB的参考

Fil*_*ves 6

这是未定义的行为.

C99第6.2.7.2节规定:

引用同一对象或函数的所有声明都应具有兼容类型; 否则,行为未定义.

注意:如下面的评论中所述,这里的重要部分是[...]引用相同的对象[...],在6.2.2中进一步定义:

在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能.

关于数组类型的类型兼容性规则,C99的6.7.5.2.4节阐明了两种数组类型兼容的含义:

要使两个数组类型兼容,两者都应具有兼容的元素类型,如果两个大小说明符都存在,并且是整数常量表达式,则两个大小说明符应具有相同的常量值.如果在要求它们兼容的上下文中使用这两种数组类型,则如果两个大小说明符计算为不相等的值,则它是未定义的行为.

(强调我的)

在现实世界中,只要您坚持使用1D数组,它就可能是无害的,因为没有边界检查,并且无论大小说明符如何,第一个元素的地址都保持不变,但请注意,sizeof运算符将返回不同的值在每个源文件中(打开编写错误代码的绝佳机会).

如果您决定对此示例进行推断并声明具有不同尺寸大小的多维数组,事情开始变得非常难看,因为数组中每个元素的偏移量将不再与实际尺寸匹配.

  • 值得注意的是,如果声明只是省略了大小,那么两个数组类型将是兼容的并且没有问题(只要使用该数组的代码有某种方法可以避免无效索引).当然,在这种情况下,你不能使用`sizeof`运算符,因为它不能应用于不完整的类型. (3认同)