传递静态const int作为参考时链接器错误

时间:2015-03-25 14:59:37

标签: c++ c++11 gcc

使用gcc 4.6.3编译时,为什么会向NUMBER输入未定义的引用错误?:

g++ -std=c++0x -pipe -Wall -pedantic file.c

file.c:

#include <stdio.h>
#include <utility>

class Thing {
public:
    Thing() {
        foo(NUMBER);
        const int* p = &NUMBER;
        printf("%d\n", *p);
    }
    void foo(const int& i) {}
    static const int NUMBER = 123;
};

int main() { Thing thing; return 0; }

错误:

chetic@home:~/Documents$ g++ -std=c++0x -pipe -Wall -pedantic test.c 
/tmp/cceBY2zr.o: In function `Thing::Thing()':
statest.c:(.text._ZN5ThingC2Ev[_ZN5ThingC5Ev]+0x11): undefined reference to `Thing::NUMBER'
statest.c:(.text._ZN5ThingC2Ev[_ZN5ThingC5Ev]+0x21): undefined reference to `Thing::NUMBER'

我在这里被称为#3:http://eel.is/c++draft/class.static.data/#3 但是我希望有人可以用更简单的术语来解释它。

为什么编译器没有给我一个可读的错误,或者为什么不将NUMBER视为变量?

另外,为什么这会出现链接器错误?

2 个答案:

答案 0 :(得分:6)

当您获取地址或绑定对NUMBER的引用时:

foo(NUMBER);            // bind a reference
const int* p = &NUMBER; // taking address

你是odr-using变量,这意味着它需要一个行外定义:

const int Thing::NUMBER ;

从上面引用cppreference:

  

非正式地说,如果一个对象的地址被占用,或者一个引用被绑定到该对象上,那么该对象就会被使用,如果对它进行函数调用或者使用它的地址,则该函数会被使用。如果一个对象或函数使用了odr,它的定义必须存在于程序的某个地方;违反这一点的是链接时错误。

Jonathan Wakely在上面的评论中提供了一个很好的参考:undefined reference to `S::a'

答案 1 :(得分:3)

您必须定义静态数据成员。例如

const int Thing::NUMBER;

在类中,仅声明静态数据成员。如果编译器不需要其地址,则不需要其定义。但是,您的代码使用数据成员的地址

const int* p = &NUMBER;

因此编译器必须定义常量。