当extern声明和定义之间存在不匹配的类型时,行为是什么?

时间:2013-02-04 23:33:10

标签: c++ linker extern undefined-behavior typechecking

假设我有两个文件:

== File1中==

extern char* foo;

==文件2 ==

double foo;

尽管类型不匹配,这两个文件似乎可以编译和链接g ++和clang ++。据我所知,建议的做法是将extern声明放在两个文件都包含的标题中,这样File2就会抛出重定义错误。

我的问题是:

  • 根据c ++标准,这会导致未定义的行为吗?如果不是File1中 foo 的内容?
  • 联系人可以抓住这种类型的不匹配吗?

2 个答案:

答案 0 :(得分:3)

  

根据c ++标准,这会导致未定义的行为吗?

嗯,真正的问题是这是未定义的行为还是标准将其指定为格式错误的(标准用语)。因为,显然,这是不正确的。我试图从标准中找到关于此的东西,但无济于事。但是,在许多类似的情况下,例如,decl / def的不匹配或在链接器上抛出时髦的东西(参见第3.5,7.5节,或搜索“extern”或“linkage”),标准通常最终会说:< / p>

该计划格式错误,无需诊断。

所以,我敢打赌,假设这也是这种情况,这是非常安全的。这意味着这是错误的代码,比“未定义的行为”更糟糕,因为UB通常会对特定的实现有某种合理的行为(尽管你不应该推测这种行为会是什么,当然也不会依赖于炒)。标准中使用了“格式错误”这个术语,你可以或多或少地推断它意味着代码是FUBAR。这也意味着标准不要求链接器以允许它捕获这种错误的方式实现,这就是它正确编译和链接的原因,但是当你运行它时坚持你的袜子

  

联系人能否抓住这种类型的不匹配?

理论上,是的。链接器实现可以将变量的类型(使用名称修改)编码到其外部符号中,从而能够限制与类型匹配的事物的链接(例如,像重载函数),或者在发生诊断(错误)时它遇到类型不匹配。我认为与标准相比,前者过于宽松。

但是,我所知道的所有编译器都不会破坏变量的名称,因此,您可以假设这种不匹配是“格式错误,无需诊断”。

答案 1 :(得分:2)

  

根据c ++标准,这会导致未定义的行为吗?

是的,绝对是的。

  

如果不是File1中foo的内容?

嗯,它的值为零,因为double foo;未设置为任何值。但是因为你不能依赖零值实际上与指针的NULL相同,所以如果你试图以某种方式将foo作为指针与foo进行比较,则无法说明会发生什么一双。

当然,如果指定了指针foo,例如foo = malloc(100);,然后double foo将包含指针的位,这很可能不是一个特别好的浮点数 - 很可能是64位系统上的非法指针,如前几位很可能是零,这往往意味着该值为零,在这种情况下,其余的位也应该为零。虽然,它确实取决于浮点的内部格式,以及指针的实际值

  

联系人能否抓住这种类型的不匹配?

不,即使在C ++中,变量的名称也不会被“修改”。只有函数具有编码到函数名称中的函数类型。

从技术上讲,链接器或某些编译器组件可以跟踪符号所代表的类型,然后给出错误或警告。但是标准没有要求这样做。你需要做正确的事。