编译后的文件没有任何变化。它将生成完全相同的二进制文件!
如果您将两个版本编译到单个可执行文件中,就像这样:
bool isFoo(const char* bar) {
return !strcmp(bar, "some_long_complicated_name");
}
const char FOO_NAME[] = "some_long_complicated_name";
bool isFoo2(const char* bar) {
return !strcmp(bar, FOO_NAME);
}
int main()
{
isFoo( "nnn" );
isFoo2( "nnn" );
}
您可以调查二进制文件:
0000000000401156 <isFoo(char const*)>:
401156: 55 push %rbp
401157: 48 89 e5 mov %rsp,%rbp
40115a: 48 83 ec 10 sub $0x10,%rsp
40115e: 48 89 7d f8 mov %rdi,-0x8(%rbp)
401162: 48 8b 45 f8 mov -0x8(%rbp),%rax
401166: be c0 20 40 00 mov $0x4020c0,%esi
40116b: 48 89 c7 mov %rax,%rdi
40116e: e8 cd fe ff ff callq 401040 <strcmp@plt>
401173: 85 c0 test %eax,%eax
401175: 0f 94 c0 sete %al
401178: c9 leaveq
401179: c3 retq
000000000040117a <isFoo2(char const*)>:
40117a: 55 push %rbp
40117b: 48 89 e5 mov %rsp,%rbp
40117e: 48 83 ec 10 sub $0x10,%rsp
401182: 48 89 7d f8 mov %rdi,-0x8(%rbp)
401186: 48 8b 45 f8 mov -0x8(%rbp),%rax
40118a: be e0 20 40 00 mov $0x4020e0,%esi
40118f: 48 89 c7 mov %rax,%rdi
401192: e8 a9 fe ff ff callq 401040 <strcmp@plt>
401197: 85 c0 test %eax,%eax
401199: 0f 94 c0 sete %al
40119c: c9 leaveq
40119d: c3 retq
这里是字符串的位置:
4020c0 736f6d65 5f6c6f6e 675f636f 6d706c69 some_long_compli
4020d0 63617465 645f6e61 6d650000 00000000 cated_name......
4020e0 736f6d65 5f6c6f6e 675f636f 6d706c69 some_long_compli
4020f0 63617465 645f6e61 6d65006e 6e6e00 cated_name.nnn.
您在这里还可以看到“nnn”字符串!
输出是通过以下方式生成的:
objdump -s -S go | c++filt > x
注意:您必须使用
-O0
进行编译,否则编译器会聪明地在编译时完成所有工作。如果我使用
-O2
,则无法再看到任何字符串,并且所有调用结果已经存在于二进制文件中。很高兴看到编译器在编译时能够完成多少工作!
因此,没有任何区别,完全相同的二进制代码。但是通过标准优化,不需要为字符串比较生成代码,因为已经在编译时完成了!
我修改了main函数以查看比较结果在何处使用:
int main()
{
volatile bool x;
x = isFoo( "nnn" );
x = isFoo2( "nnn" );
}
产生的二进制文件:
0000000000401060 <main>:
}
int main()
{
volatile bool x;
x = isFoo( "nnn" );
401060: c6 44 24 ff 00 movb $0x0,-0x1(%rsp)
x = isFoo2( "nnn" );
}
401065: 31 c0 xor %eax,%eax
x = isFoo2( "nnn" );
401067: c6 44 24 ff 00 movb $0x0,-0x1(%rsp)
}
40106c: c3 retq
正如您所看到的,比较的结果已经存在于编译代码中。在运行时不再比较任何字符串。
关于速度和内存使用方面的所有问题:测量!如您在示例中所见,结果与其他答案中的大多数假设不同。如果速度或内存占用真的很重要:请查看编译器生成的结果。通常它比您想象的更完美!
FOO_NAME
将在符号表中可见,以及(2)在第一个版本中,在某些(通常较旧的)编译器下,该数组将不被标记为const
。但除此之外,字符串字面值的实现是作为一个无名的静态字符数组。(是的,运行时内存使用可能是相同的。) - Steve Summitstrcmp()
的第二个参数的数组将作为数组第一个字节的地址传递给函数。实际的数组将在编译时生成(并链接到只读内存)。因此,在这两种情况下,strcmp()
将只传递一个内存指针。 - user3629249