首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++ const符号膨胀链接文件

c++ const符号膨胀链接文件
EN

Stack Overflow用户
提问于 2011-09-29 14:22:38
回答 4查看 258关注 0票数 2

在C++中,在头文件中放置const是合法的,通常C方法是将extern声明放在头中,而定义放在一个编译单元中,但在C++中,由于链接时符号没有被删除(用gnu ld和visual studio测试),前一种技术导致二进制值的增加。有什么好办法做这些事吗?我只能想到一种定义或C方式,但后者可能给较少的优化留出空间..。

代码语言:javascript
复制
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$
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-09-29 14:26:07

你有两个真正的选择。可以用外部链接定义常量,也可以不定义常量。通过内部链接,假设打开优化,每个实际使用常量的翻译单元中只会有一个副本。

内部联系:

代码语言:javascript
复制
// a.h
const double AI_LIKE_COOKIES = 5.0;

外部联系:

代码语言:javascript
复制
// a.h
extern const double AI_LIKE_COOKIES;

// a.c
const double AI_LIKE_COOKIES = 5.0;

然而,,您可能会问,“内联常量怎么办?”不幸的是,浮点操作数实际上不能内联。每当您在函数中使用浮点常量时,该值将作为常量存储在内存中。考虑这两项职能:

代码语言:javascript
复制
// 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的两份副本,就好像您已经这样做了:

代码语言:javascript
复制
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,并在一个翻译单元中定义常量。代码可能不会更慢,除非链接时间优化,这是确保最终产品中只有一个副本的唯一好方法。

听起来好像有八字节的麻烦,不过.

汇编程序:

这里有一个函数:

代码语言:javascript
复制
double func(double x)
{
    return x + 5.0;
}

下面是x86_64上的汇编程序:

代码语言:javascript
复制
_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中。在每个使用常量的翻译单元中,你仍然会得到一个常量的副本。

票数 2
EN

Stack Overflow用户

发布于 2011-09-29 14:41:53

声明为const的对象和未显式声明的extern在C++中具有内部链接。这意味着每个翻译单元都获得自己的对象副本。

但是,由于它们有内部链接,因此不能从其他翻译单元中命名,编译器可以检测对象本身是否被使用--对于基本的const对象,这只是意味着它的地址从未被取走;它的值可以根据需要被替换-并且从对象文件中省略它。

gcc甚至会在-O1上执行这一优化。

代码语言:javascript
复制
$ 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
$ 
票数 6
EN

Stack Overflow用户

发布于 2011-09-29 14:28:40

在每个标题中隐式地放置const使其内部链接,因此它在每个翻译单元中都是重复的。我相信,"C方式“是处理这一问题的正常方法。

您还可以使用简单的内联函数定义“常量”(请参阅std::numeric_limits<T>::max())。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7598758

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档