static const 变量没有(至少不应该)在堆栈上创建;加载程序时会为它们留出空间,因此不应存在与创建它们相关的运行时损失。
可能与它们的初始化相关联的运行时惩罚。尽管我使用的 gcc 版本在编译时初始化了常量;我不知道这种行为有多普遍。如果存在这样的运行时惩罚,它只会在程序启动时发生一次。
除此之外,静态const-qualified 对象和字面量1(宏最终将扩展为)之间的任何运行时性能差异应该可以忽略不计,具体取决于关于字面量的类型和所涉及的操作。
愚蠢的例子(gcc version 4.1.2 20070115 (SUSE Linux)):
#include <stdio.h>
#define FOO_MACRO 5
static const int foo_const = 5;
int main( void )
{
printf( "sizeof FOO_MACRO = %zu\n", sizeof FOO_MACRO );
printf( "sizeof foo_const = %zu\n", sizeof foo_const );
printf( " &foo_const = %p\n", ( void * ) &foo_const );
printf( "FOO_MACRO = %d\n", FOO_MACRO );
printf( "foo_const = %d\n", foo_const );
return 0;
}
输出:
sizeof FOO_MACRO = 4
sizeof foo_const = 4
&foo_const = 0x400660
FOO_MACRO = 5
foo_const = 5
foo_const 的地址在二进制文件的 .rodata 部分中:
[fbgo448@n9dvap997]~/prototypes/static: objdump -s -j .rodata static
static: file format elf64-x86-64
Contents of section .rodata:
40065c 01000200 05000000 73697a65 6f662046 ........sizeof F
^^^^^^^^
40066c 4f4f5f4d 4143524f 203d2025 7a750a00 OO_MACRO = %zu..
40067c 73697a65 6f662066 6f6f5f63 6f6e7374 sizeof foo_const
40068c 203d2025 7a750a00 20202020 20202666 = %zu.. &f
40069c 6f6f5f63 6f6e7374 203d2025 700a0046 oo_const = %p..F
4006ac 4f4f5f4d 4143524f 203d2025 640a0066 OO_MACRO = %d..f
4006bc 6f6f5f63 6f6e7374 203d2025 640a00 oo_const = %d..
请注意,对象已经初始化为 5,因此没有运行时初始化惩罚。
在printf 语句中,将foo_const 的值加载到%esi 的指令比加载文字值0x5 的指令需要多一个字节,并且该指令必须有效地取消引用@987654333 @注册:
400538: be 05 00 00 00 mov $0x5,%esi
^^^^^^^^^^^^^^
40053d: bf ab 06 40 00 mov $0x4006ab,%edi
400542: b8 00 00 00 00 mov $0x0,%eax
400547: e8 e4 fe ff ff callq 400430 <printf@plt>
40054c: 8b 35 0e 01 00 00 mov 270(%rip),%esi # 400660 <foo_const>
^^^^^^^^^^^^^^^^^
400552: bf bb 06 40 00 mov $0x4006bb,%edi
400557: b8 00 00 00 00 mov $0x0,%eax
40055c: e8 cf fe ff ff callq 400430 <printf@plt>
这会转化为可衡量的运行时性能差异吗?也许,在合适的情况下。如果您在紧密循环中执行数十万次 CPU 绑定的操作,那么是的,在 static const 变量上使用宏(解析为文字)可能会明显更快。如果这是在程序的生命周期内发生一次的事情,那么差异太小而无法衡量,并且没有令人信服的理由在 static const 变量上使用宏。
与往常一样,正确性和可维护性比性能更重要2。使用static const 而不是宏,您不太可能出错。考虑以下场景:
#define FOO 1+2
...
x = FOO * 3;
你会期待什么答案,你会得到什么答案?比较一下
static const int foo = 1+2;
...
x = foo * 3;
是的,您可以通过使用括号 - (1 + 2) 来修复宏大小写。关键是,如果您使用 static const 对象,这种情况就不是问题。这是一种更少的射击自己的方式。
1. 现在,我只讨论简单的标量文字(整数或浮点数),而不是复合文字;尚未调查他们的行为。
2. 如果你的代码给出了错误的答案或做错了事,你的代码有多快并不重要。如果没有人可以修复或升级它,因为他们无法理解它是如何工作的,那么你的代码有多快并不重要。如果您的代码在输入错误的第一个提示时死亡,那么它的速度有多快并不重要。如果您的代码打开了恶意软件的大门,那么它的速度并不重要。