最近和同事讨论的一个问题:

#include

using namespace std;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Foo
{
public:
static const int MEMBER1 = 1;
static const int MEMBER2 = 2;
};

int main()
{

bool a = true;

int x = 0;
if (a == true)
{
x = Foo::MEMBER1;
}
else
{
x = Foo::MEMBER2;
}
cout<<a<<endl;


int y = a ? Foo::MEMBER1 : Foo::MEMBER2;
cout<<y<<endl;

return 0;
}

1.g++ -o a.o a.cpp 报错(28行)

/tmp/cccWCuHP.o: In function main’:
a.cpp:(.text+0x4e): undefined reference to Foo::MEMBER1′
a.cpp:(.text+0x56): undefined reference to `Foo::MEMBER2′

2.将28行改为int y = true ? Foo::MEMBER1 : Foo::MEMBER2

编译通过

3.如果在外部声明:

cont int Foo::MEMBER1;
cont int Foo::MEMBER2;
编译通过

4.g++ -o2编译的时候是通过的

问题分析:
1.g++ -E a.cpp -o a.i(预处理)
查看a.i文件:

18384 using namespace std;
18385
18386 class Foo
18387 {
18388 public:
18389 static const int MEMBER1 = 1;
18390 static const int MEMBER2 = 2;
18391 };
18392
18393 int main()
18394 {
18395 bool a = true;
18396
18397 int x = 0;
18398 if (a == true)
18399 {
18400 x = Foo::MEMBER1;
18401 }
18402 else
18403 {
18404 x = Foo::MEMBER2;
18405 }
18406 cout<<a<<endl;
18407
18408
18409 int y = a ? Foo::MEMBER1 : Foo::MEMBER2;
18410 cout<<y<<endl;
18411
18412 return 0;
18413 }
并没有做特别的处理。

2.编译:
g++ -S a.i -o a.s

3.转化成可读的模式
cat a.s | c++filt > a.t

查看a.t

18398 if (a == true)
18399 {
18400 x = Foo::MEMBER1;
18401 }
18402 else
18403 {
18404 x = Foo::MEMBER2;
18405 }

翻译为:(使用的是整数替换)

20 je .L2
21 movl $1, -8(%rbp)
22 jmp .L3
23 .L2:
24 movl $2, -8(%rbp)

int y = a ? Foo::MEMBER1 : Foo::MEMBER2;
翻译为:(取地址)

33 cmpb $0, -9(%rbp)
34 je .L4
35 movl Foo::MEMBER1(%rip), %eax
36 jmp .L5
37 .L4:
38 movl Foo::MEMBER2(%rip), %eax

int y = true ? Foo::MEMBER1 : Foo::MEMBER2;
翻译为:(整数替换)
33 movl $1, -4(%rbp)
34 movl -4(%rbp), %eax
35 movl %eax, %esi

-o2优化时的汇编代码也是直接整数替换

其它根本原因应该是:
1)类内部进行初始化”的static const成员变量实际上是根本没有分配内存空间。
2)至于为什么替换为if .. else则编译通过是因为替换成if .. else后因为I和J是rvalue,所以编译通过而在三元表达式中由于第二个操作符和第三个操作符是相同类型同时无法在编译器计算所以是I和J要求lvalue,所以导致编译报错
参考URL:
1)http://rdc.taobao.com/blog/cs/?p=153
2)http://stackoverflow.com/questions/272900/c-undefined-reference-to-static-class-member

Comments

2012-06-21