TL:DR: 使用gcc -fno-builtin-strcmp
so strcmp()
不被视为等同于__builtin_strcmp()
. 禁用优化 https://stackoverflow.com/questions/53366394/why-does-clang-produce-inefficient-asm-with-o0-for-this-simple-floating-point,GCC 只能在单个语句内进行常量传播,而不能跨语句进行常量传播。实际的库版本减去不同的字符;编译时 eval 可能会将结果标准化为 1 / 0 / -1,这不是 ISO C 所要求或保证的。
您很可能会看到编译器优化的结果。要是我们在 godbolt 上使用 gcc 测试代码 http://gcc.godbolt.org/#%7B%22version%22%3A3%2C%22filterAsm%22%3A%7B%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue%2C%22colouriseAsm%22%3Atrue%7D%2C%22compilers%22%3A%5B%7B%22sourcez%22%3A%22MQSwdgxgNgrgJgUwAQB4DOAXOID2A6ACwD4AoUSWRVTAJ3AHNDSTwMkBbAQ3AAoBKAN4kSSUUgD04gA6c0aBkloM0SbDQQQMUAJ4ixUumAwAzHgCIApHAA6YMwBpFGGhHZTznAlzgOkZ45wYCFxmfHwA3MJiEtKy8mD0Tob0KrJIUjisCDQqeqIQBJw0SABUnAC8fp7eZpHRBUWlAEaV%2FoHBnLV56YYm5la2DrSu7pz2TWGR3eoYMDRgSAAMUwC%2BQAA%3D%22%2C%22compiler%22%3A%22%2Fopt%2Fgcc-4.9.0%2Fbin%2Fg%2B%2B%22%2C%22options%22%3A%22-x%20c%20-std%3Dc99%20-O0%20-fverbose-asm%20-fno-inline-small-functions%22%7D%5D%7D, with -O0
优化级别,我们可以看到第一种情况它没有调用strcmp
:
movl $-1, %esi #,
movl $.LC0, %edi #,
movl $0, %eax #,
call printf #
由于您使用常量作为参数strcmp http://en.cppreference.com/w/c/string/byte/strcmp编译器能够执行不断折叠 http://en.wikipedia.org/wiki/Constant_folding并致电编译器内在 http://en.wikipedia.org/wiki/Intrinsic_function在编译时并生成-1
然后,不必调用strcmp
在运行时,它在标准库中实现,并且将具有不同的实现,然后可能更简单的编译时strcmp
.
在第二种情况下,它确实会生成一个调用strcmp
:
call strcmp #
movl %eax, %esi # D.2047,
movl $.LC0, %edi #,
movl $0, %eax #,
call printf #
这与事实是一致的gcc 有一个内置的 strcmp https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html,这是什么gcc
将在不断折叠时使用。
如果我们进一步测试使用-O1优化级别或更高 http://gcc.godbolt.org/#%7B%22version%22%3A3%2C%22filterAsm%22%3A%7B%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue%2C%22colouriseAsm%22%3Atrue%7D%2C%22compilers%22%3A%5B%7B%22sourcez%22%3A%22MQSwdgxgNgrgJgUwAQB4DOAXOID2A6ACwD4AoUSWRVTAJ3AHNDSTwMkBbAQ3AAoBKAN4kSSUUgD04gA6c0aBkloM0SbDQQQMUAJ4ixUumAwAzHgCIApHAA6YMwBpFGGhHZTznAlzgOkZ45wYCFxmfHwA3MJiEtKy8mD0Tob0KrJIUjisCDQqeqIQBJw0SABUnAC8fp7eZpHRBUWlAEaV%2FoHBnLV56YYm5la2DrSu7pz2TWGR3eoYMDRgSAAMUwC%2BQAA%3D%22%2C%22compiler%22%3A%22%2Fopt%2Fgcc-4.9.0%2Fbin%2Fg%2B%2B%22%2C%22options%22%3A%22-x%20c%20-std%3Dc99%20-O3%20-fverbose-asm%20-fno-inline-small-functions%22%7D%5D%7D 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
and b
也指向编译时已知的常量,并且还可以计算结果strcmp
对于这种情况,以及在编译时。
我们可以确认gcc
正在通过构建来使用内置函数-fno-内置标志 https://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/C-Dialect-Options.html并观察到调用strcmp
将为所有情况生成。
clang
略有不同,因为它根本不折叠使用-O0
但会在以下位置弃牌-O1
及以上两者。
请注意,任何负面结果都是完全符合的,我们可以通过查看 C99 标准草案部分看到7.21.4.2
strcmp 函数表示 (强调我的):
int strcmp(const char *s1, const char *s2);
strcmp 函数返回一个大于、等于的整数或更少
大于零,因此当 s1 指向的字符串大于时,
等于,或小于字符串s2 所指向的。
technosurus 指出strcmp
指定将字符串视为由以下内容组成无符号字符,这在 C99 下有介绍7.21.1
其中说:
对于本节中的所有功能,每个字符应
解释为好像它具有 unsigned char 类型(因此每个
可能的对象表示是有效的并且具有不同的值)。