为什么使用extern struct {} foo,用g ++触发无效的fPIC必需的错误消息?

时间:2015-05-04 20:43:36

标签: c++ gcc

我正在构建一个共享库,它具有相应的代码和编译规则,如下所示:

// x.C
struct {
   short len;
   char s[32700];
   } foo;

// u.C
extern struct {
   short len;
   char s[32700];
   } foo;

void blah(void)
{
   foo.s[0] = 0 ;
}

$CXX -c x.C -fPIC
$CXX -c u.C -fPIC
$CXX -shared -o x.so.1 -Wl,-soname,x.so.1 x.o u.o

此代码编译并链接到intel(v13-v16)编译器和clang编译器(v3.6),但是使用g ++(版本4.9.2),我收到链接错误:

u.o: relocation R_X86_64_PC32 against undefined symbol `foo' can not be used when making a shared object; recompile with -fPIC

这里关于-fPIC的链接错误显然是错误的,因为代码是用fPIC编译的。我还在objdump -x输出中看到符号的重定位记录:

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
0000000000000006 R_X86_64_PC32     foo-0x0000000000000003

clang和gcc编译器都会产生警告,指导纠正允许它链接的代码(至少这个独立版本,实际代码将更难找出修复的位置和方法):

u.C:5:10: warning: anonymous type with no linkage used to declare variable '<anonymous struct> foo' with linkage
        } foo;
          ^

我确实可以通过删除匿名结构来解决这个问题:

// u.h
struct fooT {
   short len;
   char s[32700];
   } ;

extern fooT foo ;

// u.C
#include "u.h"

void blah(void)
{
   foo.s[0] = 0 ;
}

// x.C
#include "u.h"

struct fooT foo ;

所以,虽然我有一个修复,但我想了解这里发生了什么。我看到一些有类似链接错误的问题:

其中一些表明这可能与符号可见性有关。 gcc是否标记此符号是否会触发最终的链接错误? g ++,clang ++或intel编译器中的哪一个在这里表现得正确或不正确,或者这个构造是无效的,只是简单的不可移植?如果这是无效代码,那么C ++标准的哪个部分违反了?

1 个答案:

答案 0 :(得分:4)

我正在阅读3.5部分,并且假设我正确阅读了所有内容,您的非typedef未命名类没有链接,因此不能称为extern

让我们快速回顾一下:

第一和第二段是定义和序言。

/3有多种原因可以说是内部联系。它们似乎都不适用(static,const / constexpr,匿名联合)。

/4都与未命名的命名空间相关

/5类范围和typedef范围不适用的内容。

/6阻止不适用的范围项目。

/7更多块范围项。

/8我们在这里Names not covered by these rules have no linkage....

因此,我认为链接器只是因为你试图extern引用没有链接的东西而感到困惑。虽然错误信息似乎很糟糕/措辞不佳,但它似乎很好地发出错误。