32位和64位系统中的strcmp行为

时间:2013-08-07 05:49:13

标签: c 32bit-64bit strcmp

以下代码在32位和64位操作系统中表现不同。

char *cat = "v,a";
if (strcmp(cat, ",") == 1)
    ...

上述条件在32位中为真,但在64位中为假。我想知道为什么会有所不同? 32位和64位操作系统都是Linux(Fedora)。

3 个答案:

答案 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功能

     

¶3strcmp函数返回一个大于,等于或小于零的整数,   因此,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()函数仅保证使用正确的符号返回结果,并且幅度是体系结构/实现特定的。