根据 OSX Darwin 上的 man memcmp
:
但是,当我对此进行测试时:
#include <stdio.h>
#include <string.h>
int main()
{
printf("%i\n", memcmp("\200", "\0", 1));
return (0);
}
它显示
-1
,这表明 \200
小于 \0
。对此有什么解释吗?
根据
gcc --version
的编译器版本是“Apple LLVM version 9.0.0 (clang-900.0.39.2)”,系统运行的是 High Sierra 10.13.4 最佳答案
这是一个编译器错误。当两个参数都是文字时,编译器错误地评估对 memcmp
的调用。当实际调用 memcmp
时,它返回预期的结果。
以下内容在 macOS 10.13.4 (17E199) 上使用 Apple LLVM 9.1.0 (clang-902.0.39.1) 版进行了测试。我用“clang -std=c11”编译,用“-O0”或“-O3”来选择优化级别,用“-S”来生成程序集。
考虑对 memcmp
的四种替代调用:
printf("%i\n", memcmp("\200", "\0", 1));
printf("%i\n", memcmp((char[] ) { '\200' }, "\0", 1));
printf("%i\n", memcmp((unsigned char[] ) { '\200' }, "\0", 1));
char a[1] = { 128 };
char b[1] = { 0 };
printf("%i\n", memcmp(a, b, 1));
对于前两次调用,编译器生成 不正确的 程序集,将硬编码值 -1 传递给
printf
。没有调用 memcmp
;它已被优化掉,即使在“-O0”版本中也是如此。 (在“-O0”版本中,-1 被编码为 4294967295,这在其上下文中是等效的。)当使用字符串文字或复合文字调用 memcmp
时,其返回值在编译时是已知的,因此编译器已评估它。然而,它这样做是错误的。对于第三次调用,编译器生成 不正确的 程序集,该程序集传递了硬编码值 1。这表明编译器在其计算中(错误地)使用了文字类型。
对于第四次调用,我们使用定义的非文字对象,“-O0”版本调用
memcmp
。运行时,程序打印 正确的 结果,128。对于“-O3”版本,编译器生成 正确的 程序集,其硬编码值为 128。因此,编译器 是否 具有正确评估 memcmp
的算法在编译时,但它对文字的情况使用了不同的错误算法。当使用一种文字和一种非文字时,编译器会生成正确的代码。这解释了为什么以前没有发现和修复此错误:使用两个文字调用
memcmp
的情况很少见,同时执行此操作并取决于结果的大小或使用设置了高位的字符的代码很少见。(我向 Apple 报告了这个错误。)
关于c - BSD memcmp(3) 手册和实现的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50433145/