我们的C代码库跨两个文件存储所有全局常量:

//global.h
extern const long double ACCELERATION_GRAVITY_FTS;
extern const long double PI;
extern const long double DEG_TO_RAD;
extern const long double RAD_TO_DEG;
extern const long double GC_NM_PER_RAD;
extern const long double FEET_PER_NM;
...

//global.c
const long double ACCELERATION_GRAVITY_FTS = 32.17405;
const long double PI = 3.1415926535897932384626433832795;
const long double DEG_TO_RAD = 0.01745329251994329576923690768489;
const long double RAD_TO_DEG = 57.295779513082320876798154814105;
const long double GC_NM_PER_RAD = 3437.74677471314;
const long double FEET_PER_NM = 6076.1155;

为了避免重复,我想将它们重构为一个文件:
//global.h
static const long double ACCELERATION_GRAVITY_FTS = 32.17405;
static const long double PI = 3.1415926535897932384626433832795;
static const long double DEG_TO_RAD = 0.01745329251994329576923690768489;
static const long double RAD_TO_DEG = 57.295779513082320876798154814105;
static const long double GC_NM_PER_RAD = 3437.74677471314;
static const long double FEET_PER_NM = 6076.1155;
//global.c no longer exists

尽管从可维护性的角度来看,这显然是一个很好的重构,
对于性能和可执行文件大小是否实用?

最佳答案

除非static const或由函数初始化,否则volatile变量将是编译时常量。
(无论如何,使用任何合适的优化编译器)
所以如果你使用static const变量,你可以得到一个速度增加和一个更小的二进制数。
例如:

extern volatile const int n;

int main(){
    volatile int i = n;
}

volatile const int n = 5;

其中包含x86程序集:
main:
    mov eax, DWORD PTR n[rip]
    mov DWORD PTR [rsp-4], eax
    xor eax, eax
    ret
n:
    .long   5

我们必须使用volatile来强制编译器获取变量的地址(如果变量不是volatile而是在另一个转换单元中,则会发生这种情况),而不是优化int i
static const相同的例子:
static const int n = 5;

int main(){
    volatile int i = n;
}

具有x86程序集:
main:
    mov DWORD PTR [rsp-4], 5
    xor eax, eax
    ret

我们不必对常量使用volatile,因为我们将以与使用头完全相同的方式公开变量,但是我们仍然需要停止编译器优化i
您可以看到,static const方法少了一条指令,extern方法在二进制文件中添加了额外的数据,用于需要存储以供参考的文本。
所以我们得到了更好的性能和更小的二进制文件。尽管,我承认,这些例子都是微不足道的。
实际上,这也不是一个完美的表现。如果在另一个翻译单元中定义了const int n,如果没有链接时间优化,编译器将无法输出n: .long 5,并且必须引用另一个变量。但我们会给这个例子带来怀疑的好处。
这些优化是非常常见的,您基本上可以依赖它的可用性。
唯一要注意的是如果你写了这样的东西:
static const int n = some_func();

int main(){
    volatile int i = n;
}

编译器将无法用n替换其文本值。这会给二进制文件添加膨胀,因为您在头中定义它,并且它将在每个转换单元中重新声明一次。因此,在这种情况下,extern对空间更有利,但可能不是在速度上;您可以自己测试。如果你真的需要微观优化,只需混合和匹配。
[所有示例都是用GCC4.9.2从https://gcc.godbolt.org/中编译的,并使用标志-O3]

关于c - 用“静态常量”替换“外部常量”会影响性能吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32491639/

10-10 22:42
查看更多