将 'extern const' 替换为 'static const' 会影响性能吗?

Will replacing 'extern const' with 'static const' affect performance?

我们的 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

虽然这在可维护性方面显然是一个很好的重构,
它对性能和可执行文件大小是否实用?

不,我认为这不会影响性能或可执行文件的大小。 (相反,它可能会提高性能。)

可能有充分的理由更喜欢 extern。 例如:您的 const long double 值被编译到共享库中。对于使用该库的任何程序,当您更改已编译的库时,这些 const 变量会相应地更改。也就是说你只有在re-compile共享库的时候才想改变它们的值。相比之下,如果在这种情况下使用单个 header,则需要 re-compile 所有程序才能使它们更新。

您的建议是有效代码,它可能提高您的运行速度并且可能增加您的可执行文件的大小。

在这两种情况下,这取决于您的编译器在优化方面的表现。

从概念上讲,static const 版本意味着每个翻译单元都有自己的常量副本。

但这也意味着有更强的优化能力,因为编译器可以看到常量的值;它可以直接将值包含在正在使用的任何计算中,而不是从链接的内存位置检索值。

A static const 变量将是一个 compile-time 常量,除非 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,因为我们将以与使用 header 完全相同的方式公开变量,但我们仍然需要停止编译器优化 i.

可以看到static const方式少了一条指令,extern方式在二进制中添加了额外的数据,用于需要存储以供参考的文字。

所以我们得到更好的性能一个更小的二进制文件。虽然,我承认,这些例子非常微不足道。

这实际上也不是一个完美的代表。如果我们在另一个翻译单元中定义了 const int n,没有 link-time 优化,编译器将无法输出 n: .long 5 并且必须引用另一个变量。但是我们会给出这个例子的怀疑。

这些优化非常普遍,您基本上可以相信它是可用的。

唯一要注意的是,如果你这样写:

static const int n = some_func();

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

编译器无法用 n 替换它的字面值。这会给你的二进制文件增加膨胀,因为你在 header 中定义它,并且每个翻译单元都会 re-declared 一次。所以在那种情况下 extern 对 space 会更好,但速度可能不快;你可以自己测试一下。如果您确实需要 micro-optimize.

,只需混搭即可

[所有示例均使用来自 https://gcc.godbolt.org/ 的 gcc 4.9.2 编译并使用标志 -O3]