在C++中,在头文件中放置const是合法的,通常C方法是将extern声明放在头中,而定义放在一个编译单元中,但在C++中,由于链接时符号没有被删除(用gnu ld和visual studio测试),前一种技术导致二进制值的增加。有什么好办法做这些事吗?我只能想到一种定义或C方式,但后者可能给较少的优化留出空间..。
piotr@gominola:0:/tmp$ g++ -c b.cc
piotr@gominola:0:/tmp$ g++ -c a.cc
piotr@gominola:0:/tmp$ nm a.o | c++filt | grep COOK
0000000000000000 r AI_LIKE_COOKIES
piotr@gominola:0:/tmp$ nm b.o | c++filt | grep COOK
0000000000000000 r AI_LIKE_COOKIES
piotr@gominola:0:/tmp$ g++ -o a a.o b.o
piotr@gominola:0:/tmp$ nm a | c++filt | grep COOK
0000000000400610 r AI_LIKE_COOKIES
0000000000400618 r AI_LIKE_COOKIES
piotr@gominola:0:/tmp$ cat a.h
#ifndef a_h
#define a_h
//const double A = 2.0;
//extern const double AI_LIKE_COOKIES;
const double AI_LIKE_COOKIES = 5.0;
#endif
piotr@gominola:0:/tmp$ cat a.cc
#include "a.h"
using namespace std;
extern void f();
//const double AI_LIKE_COOKIES = 2.0;
int main(int argc, char *argv[])
{
f();
}
piotr@gominola:0:/tmp$ cat b.cc
#include "a.h"
void f()
{
}
piotr@gominola:0:/tmp$发布于 2011-09-29 14:26:07
你有两个真正的选择。可以用外部链接定义常量,也可以不定义常量。通过内部链接,假设打开优化,每个实际使用常量的翻译单元中只会有一个副本。
内部联系:
// a.h
const double AI_LIKE_COOKIES = 5.0;外部联系:
// a.h
extern const double AI_LIKE_COOKIES;
// a.c
const double AI_LIKE_COOKIES = 5.0;然而,,您可能会问,“内联常量怎么办?”不幸的是,浮点操作数实际上不能内联。每当您在函数中使用浮点常量时,该值将作为常量存储在内存中。考虑这两项职能:
// In func1.c
double func1(double x) { return x + 5.7; }
// In func2.c
double func2(double x) { return x * 5.7; }很可能,这两个文件都包含一个常数5.7,然后从内存中加载。没有真正执行优化*。您得到了5.7的两份副本,就好像您已经这样做了:
extern const double CONSTANT_1, CONSTANT_2;
const double CONSTANT_1 = 5.7;
const double CONSTANT_2 = 5.7;
double func1(double x) { return x + CONSTANT_1; }
double func2(double x) { return x * CONSTANT_2; }*备注:在某些系统中,如果您知道常量将链接到同一个二进制映像中而不是从库中加载,则会得到较小的代码。
Recommendation:在头文件中使用extern,并在一个翻译单元中定义常量。代码可能不会更慢,除非链接时间优化,这是确保最终产品中只有一个副本的唯一好方法。
听起来好像有八字节的麻烦,不过.
汇编程序:
这里有一个函数:
double func(double x)
{
return x + 5.0;
}下面是x86_64上的汇编程序:
_Z4funcd:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
addsd .LC0(%rip), %xmm0
ret
.cfi_endproc
.LFE0:
.size _Z4funcd, .-_Z4funcd
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LC0:
.long 0
.long 1075052544注意符号LC0,它是一个包含值5.0的常量。内联只会使符号不可见,所以它不会出现在nm中。在每个使用常量的翻译单元中,你仍然会得到一个常量的副本。
发布于 2011-09-29 14:41:53
声明为const的对象和未显式声明的extern在C++中具有内部链接。这意味着每个翻译单元都获得自己的对象副本。
但是,由于它们有内部链接,因此不能从其他翻译单元中命名,编译器可以检测对象本身是否被使用--对于基本的const对象,这只是意味着它的地址从未被取走;它的值可以根据需要被替换-并且从对象文件中省略它。
gcc甚至会在-O1上执行这一优化。
$ g++ -O1 -c a.cc
$ g++ -O1 -c b.cc
$ g++ -o a a.o b.o
$ nm a.o | c++filt | grep COOK
$ nm b.o | c++filt | grep COOK
$ nm a | c++filt | grep COOK
$ 发布于 2011-09-29 14:28:40
在每个标题中隐式地放置const使其内部链接,因此它在每个翻译单元中都是重复的。我相信,"C方式“是处理这一问题的正常方法。
您还可以使用简单的内联函数定义“常量”(请参阅std::numeric_limits<T>::max())。
https://stackoverflow.com/questions/7598758
复制相似问题