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

时间:2015-07-17 13:01:45

标签: c linker language-lawyer

这主要是对Should definition and declaration match?

的跟进

问题

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

(您可以在my answer中找到一个工作示例来回答问题)

免责声明:

  • 我知道这很危险,不会在生产代码中执行此操作
  • 我知道如果你们两个都在同一个编译单元中(通常是通过在包含定义的文件中包含.h)编译器检测到错误
  • 我已经读过Jonathan Leffler的优秀answerHow do I use extern to share variables between source files?,但在那里找不到这个特定点的答案 - 即使Jonathan表现出更糟糕的用法......

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

2 个答案:

答案 0 :(得分:6)

这是未定义的行为。

C99第6.2.7.2节规定:

  

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

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

  

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

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

  

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

(强调我的)

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

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

答案 1 :(得分:-1)

是的,这是合法的。语言允许它。

在您的特定情况下,没有未定义的行为,因为extern声明的数组小于实际分配的数组。

它可以用于声明模块使用“未发布的”数组元素的情况。算法的内务管理(抽象隐藏)。