以下代码在32位和64位操作系统中表现不同。
char *cat = "v,a";
if (strcmp(cat, ",") == 1)
...
上述条件在32位中为真,但在64位中为假。我想知道为什么会有所不同? 32位和64位操作系统都是Linux(Fedora)。
答案 0 :(得分:12)
strcmp()
函数仅定义为如果参数1在参数2之前返回负值,如果它们相同则返回零,如果参数1在参数2之后则返回正值。
无法保证任何时候返回的值都是+1
或-1
。基于该假设的任何相等测试都是错误的。可以想象,对于给定的字符串比较,32位和64位版本的strcmp()
会返回不同的数字,但是从+1
查找strcmp()
的任何测试都存在固有缺陷。< / p>
您的比较代码应为以下之一:
if (strcmp(cat, ",") > 0) // cat > ","
if (strcmp(cat, ",") == 0) // cat == ","
if (strcmp(cat, ",") >= 0) // cat >= ","
if (strcmp(cat, ",") <= 0) // cat <= ","
if (strcmp(cat, ",") < 0) // cat < ","
if (strcmp(cat, ",") != 0) // cat != ","
请注意常见主题 - 所有测试都与0比较。您还会看到人们写道:
if (strcmp(cat, ",")) // != 0
if (!strcmp(cat, ",")) // == 0
就个人而言,我更喜欢与零进行明确的比较;我精神上将短篇小说翻译成适当的缩写(并且反复这样做)。
请注意strcmp()
的规范说:
ISO / IEC 9899:2011§7.24.4.2
strcmp
功能¶3
strcmp
函数返回一个大于,等于或小于零的整数, 因此,s1
指向的字符串大于,等于或小于s2
指向的字符串。
它没有说明+1
或-1
;你不能只依赖于结果的大小,只能看它的符号(或者当字符串相等时它是零)。
答案 1 :(得分:5)
基于操作系统的“bittedness”,标准函数不会表现出不同的行为,除非您正在做一些愚蠢的事情,例如,不包括相关的头文件。除非您违反规则,否则他们必须准确展示标准中指定的行为。否则,编译器在关闭时将不是C编译器。
但是,根据标准,strcmp()
的返回值为零,正或负,当非零时, 保证为+/- 1。
你的表达最好写成:
strcmp (cat, ",") > 0
使用strcmp (cat, ",") == 1
的错误与您的操作系统是32位还是64位无关,而且与您误解返回值的事实有关。从ISO C11标准(我的大胆):
strcmp函数返回一个大于,等于或小于零的整数,因为s1指向的字符串大于,等于或小于指向的字符串。 S2。
答案 2 :(得分:2)
上面 Jonathan's answer 对strcmp()
保证的语义进行了详细解释。
回到原来的问题,即
问即可。为什么
strcmp()
行为在32位和64位系统中有所不同?
答案:strcmp()
在glibc中实现,其中各种架构都有不同的实现,都针对相应的架构进行了高度优化。
由于规范只是定义了返回值是3种可能性之一(-ve,0,+ ve),只要符号恰当地表明结果,各种实现都可以自由返回任何值。
在某些体系结构(在本例中为x86)中,简单地比较每个字节而不存储结果更快。因此,在错配时简单地返回 - / + 1会更快。
<子>
(注意,可以在x86上使用subb
而不是cmpb
来获得不匹配字节的幅度差异。但这需要每个字节 1 额外的时钟周期这意味着每个完整的迭代在不到30个时钟周期内运行所花费的总时间增加<3%增加。)
子>
在其他体系结构(在本例中为x86-64)中,相应字符的字节值之间的差异已作为比较的副产品提供。因此,简单地返回它而不是再次测试它们并返回 - / + 1。
两者都是完全有效的输出,因为strcmp()
函数仅保证使用正确的符号返回结果,并且幅度是体系结构/实现特定的。