TL:DR: 使用gcc -fno-builtin-strcmp
,这样strcmp()
不会被视为等同于__builtin_strcmp()
。 禁用优化, GCC只能在单个语句内进行常量传播,而不能跨语句进行。 实际的库版本会减去不同的字符;编译时评估可能会将结果规范化为1/0/-1,这并不是ISO C所要求或保证的。
你可能看到的是编译器优化的结果。如果我们在
godbolt
上使用
-O0
优化等级来
测试代码, 我们可以看到在第一个情况下它不会调用
strcmp
函数。
movl $-1, %esi #,
movl $.LC0, %edi #,
movl $0, %eax #,
call printf #
由于您在
strcmp中使用常量作为参数,编译器能够执行
常量折叠并在编译时调用
编译器内置函数,然后生成
-1
,而不是必须在运行时调用在标准库中实现的
strcmp
,该实现与可能更简单的编译时
strcmp
不同。
在第二种情况下,它确实生成对
strcmp
的调用:
call strcmp #
movl %eax, %esi # D.2047,
movl $.LC0, %edi #,
movl $0, %eax #,
call printf #
这与
gcc有一个strcmp内置函数的事实一致,这也是
gcc
在常量折叠期间使用的内容。
如果我们使用
使用-O1
优化级别或更高级别进行测试 gcc
将折叠两种情况,结果都为
-1
:
movl $-1, %esi #,
movl $.LC0, %edi #,
xorl %eax, %eax #
call printf #
movl $-1, %esi #,
movl $.LC0, %edi #,
xorl %eax, %eax #
call printf #
当优化选项打开时,优化器能够确定 a
和 b
也指向编译时已知的常量,并且还可以在编译时计算此情况下 strcmp
的结果。
我们可以通过使用 -fno-builtin flag 进行构建并观察所有情况下都会生成对 strcmp
的调用来确认 gcc
是否正在使用内置函数。
clang
稍有不同,它在 -O0
下不进行折叠,但在 -O1
及以上进行折叠。
请注意,任何负面结果都是完全符合规范的,我们可以查看 C99 草案标准第 7.21.4.2
节 strcmp 函数,其中写道(我强调):
int strcmp(const char *s1, const char *s2);
The strcmp function returns an integer greater than, equal to, or less
than zero, accordingly as the string pointed to by s1 is greater than,
equal to, or less than the string pointed to by s2.
technosurus指出strcmp
被规定为将字符串视为由unsigned char组成,这在C99下的7.21.1
中有所涵盖,其内容如下:
对于本子句中的所有函数,每个字符都应被解释为具有类型unsigned char(因此每个可能的对象表示都是有效的且具有不同的值)。
<string.h>
,而且 OP 是正确的。 - Iharob Al Asimistrcmp
зҡ„иҝ”еӣһеҖјеҸӘдҝқиҜҒдёәиҙҹж•°гҖҒйӣ¶жҲ–жӯЈж•°пјҢеӣ жӯӨдҪ е”ҜдёҖеҸҜд»ҘзңҹжӯЈдҫқиө–strcmp(a,b) == strcmp(c,d)
жҲҗз«Ӣзҡ„жғ…еҶөжҳҜдёӨж¬ЎжҜ”иҫғйғҪиҝ”еӣһйӣ¶гҖӮ - David Hammen