2

以下代码在 32 位和 64 位操作系统中的行为不同。

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

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

4

3 回答 3

12

如果参数 1 在参数 2 之前,则该strcmp()函数仅定义为返回负值,如果它们相同则返回零,或者如果参数 1 在参数 2 之后,则返回正值。

无法保证返回的值将是+1-1在任何时候。基于该假设的任何相等性测试都是错误的。可以想象,strcmp()对于给定的字符串比较,32 位和 64 位版本返回不同的数字,但任何寻找+1from的测试strcmp()都存在固有缺陷。

您的比较代码应该是以下之一:

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

它什么也没说+1or -1; 你不能依赖结果的大小,只能依赖它的符号(或者当字符串相等时它为零)。

于 2013-08-07T05:53:24.817 回答
5

标准函数不会根据您的操作系统的“bittedness”表现出不同的行为,除非您正在做一些愚蠢的事情,例如,不包括相关的头文件。除非您违反规则,否则他们必须完全表现出标准中指定的行为。否则,您的编译器虽然关闭,但不会是 C 编译器。

但是,根据标准, from 的返回值strcmp()是零、正数或负数,保证非零时为 +/-1。

你的表达最好写成:

strcmp (cat, ",") > 0

使用strcmp (cat, ",") == 1错误与您的操作系统是32位还是64位无关,而与您误解了返回值有关。来自 ISO C11 标准(我的粗体):

strcmp 函数返回一个大于、等于或小于零的整数,相应地,因为 s1 指向的字符串大于、等于或小于 s2 指向的字符串。

于 2013-08-07T05:51:54.977 回答
2

strcmp()上面乔纳森的回答很好地解释了由 保证的语义。


回到你原来的问题,即

。为什么strcmp()32 位和 64 位系统的行为不同?

strcmp()在 glibc 中实现,其中存在针对各种架构的不同实现,都针对相应架构进行了高度优化。

由于规范简单地定义了返回值是 3 种可能性之一(-ve、0、+ve),只要符号适当地指示结果,各种实现都可以自由地返回任何值。

  • 在某些架构(在本例中为 x86)上,简单地比较每个字节而不存储结果会更快。因此,在不匹配时简单地返回 -/+1 会更快。

    (请注意,可以使用subb而不是cmpb在 x86 上获得不匹配字节的大小差异。但这将需要每个字节额外1个时钟周期。这意味着每次完整迭代所需的总时间增加 3%运行时间少于 30 个时钟周期。)

  • 在其他架构(在本例中为 x86-64)上,相应字符的字节值之间的差异已经作为比较的副产品提供。因此,简单地返回它而不是再次测试它们并返回 -/+1 会更快。

两者都是完全有效的输出,因为strcmp()函数只能保证使用正确的符号返回结果,并且幅度是特定于架构/实现的。

于 2013-08-07T09:23:05.743 回答