根据OSX Darwin的man memcmp
:
如果两个字符串相同,则memcmp()函数返回零,否则返回0 返回前两个不同字节之间的差异(视为无符号 char值,例如
\200
大于\0
。零长度字符串 永远都是一样的。 C和可移植代码应该不需要此行为 只取决于返回值的符号。
但是,当我测试时:
#include <stdio.h>
#include <string.h>
int main()
{
printf("%i\n", memcmp("\200", "\0", 1));
return (0);
}
显示-1
,表示\200
小于\0
。
对此有任何解释吗?
根据gcc --version
的编译器版本是“Apple LLVM版本9.0.0(clang-900.0.39.2)”,系统正在运行High Sierra 10.13.4
答案 0 :(得分:2)
您的memcmp
。
我在我的OSX / Darwin系统上尝试了你的程序,得到了一个正数。所以我的系统没有错误。
但奇怪的是,我系统上的行为会有所不同,具体取决于我使用clang
还是gcc
。我认为他们使用了相同的库,但是clang
给出了128而gcc
给出了1.(或许memcmp
被实现为内置在其中一个上的编译器。)
另外,顺便提一下,我系统上的man memcmp
没有&#34; C&#34;不需要这种行为。句。
答案 1 :(得分:2)
这是编译器错误。当两个参数都是文字时,编译器会错误地评估对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.因此编译器< strong>确实有一个算法在编译时正确评估memcmp
,但它对文字的情况使用了一个不同的错误算法。
当使用一个文字和一个非文字时,编译器会生成正确的代码。这就解释了为什么以前没有看到和修复过这个错误:用{2}字符调用memcmp
的情况很少见,并且代码都是这样做的,取决于结果的大小或使用设置了高位的字符的情况比较少见。
(我向Apple报告了这个错误。)
答案 2 :(得分:-1)
这是手册中的错误。它描述了strcmp()
,当它到达其中一个字符串中的零字节时停止比较,因为那是字符串终止符;然后,较长的字符串将被视为更大("foobar"
大于"foo"
)。但memcmp()
用于比较任意内存区域,而不是字符串,因此不会特别处理零字节。
但是,这并不能解释memcmp()
返回-1
的原因。应该比较'\200'
和'\0'
,并返回正值。看起来Darwin memcmp()
将它们比作signed char
而不是unsigned char
,因此'\200'
是-128
而不是128
。如果第一个字符串是从"\200"
到"\377"
的任何内容,则会返回此错误结果。
当我在Linux上尝试您的代码时,我得到1
而不是-1
。所以这似乎是达尔文图书馆的一个错误。还有手册页中的一个错误,因为它说它们被比作unsigned char
。
我试过这个程序:
#include <stdio.h>
#include <string.h>
int main()
{
printf("memcmp: %i\n", memcmp("\200", "\0", 1));
printf("bcmp: %i\n", bcmp("\200", "\0", 1));
printf("strcmp: %i\n", strcmp("\200", "\0"));
return (0);
}
在Mac OS High Sierra上打印:
memcmp: -1
bcmp: 128
strcmp: 128
在Debian Linux上我得到了:
memcmp: 1
bcmp: 1
strcmp: 1
手册页中提到零长度字符串也是不正确的。 "\0abc"
和"\0def"
都是零长度字符串,因为字符串逻辑上以空字节结束。但他们与memcmp()
printf("memcmp: %i\n", memcmp("\0abc", "\0def", 4));
printf("bcmp: %i\n", bcmp("\0abc", "\0def", 4));
printf("strcmp: %i\n", strcmp("\0abc", "\0def"));
打印:
memcmp: -1
bcmp: -3
strcmp: 0