2

从手册页:

如果发现 s1(或其前 n 个字节)分别小于、匹配或大于 s2,则 strcmp() 和 strncmp() 函数返回一个小于、等于或大于零的整数.

C 中的示例代码(-15在我的机器上打印,交换 test1 和 test2 反转值):

#include <stdio.h>
#include <string.h>

int main() {
    char* test1 = "hello";
    char* test2 = "world";
    printf("%d\n", strcmp(test1, test2));
}

我发现这段代码(取自这个问题)依赖于 strcmp 的值,而不是 -1、0 和 1(它使用中的返回值qsort)。对我来说,这是一种糟糕的风格,并且取决于未记录的功能。

我想我有两个相关的问题:

  • C 标准中是否有定义返回值除了小于、大于或等于零之外的内容吗?如果不是,标准实现是做什么的?
  • Linux、Windows 和 BSD 的返回值是否一致?

编辑:

离开我的电脑 5 分钟后,我意识到有问题的代码实际上没有错误。我在阅读评论/答案之前删除了我想出的部分,但我把它们留在那里以保持评论的相关性。我认为这仍然是一个有趣的问题,并且可能会导致习惯于总是返回 -1、0 或 1 的其他语言的程序员打嗝(例如 Python 似乎这样做,但它没有以这种方式记录)。

FWIW,我认为依赖记录行为以外的东西是不好的风格。

4

7 回答 7

7

C 标准中是否有定义返回值除了小于、大于或等于零之外的内容吗?

不,最严格的约束是它应该为零、小于零或大于零,如此特定函数的文档中所指定。

如果不是,标准实现是做什么的?

没有“标准实现”之类的东西。即使有,也可能只是

return zero, less than zero or more than zero;

:-)

Linux、Windows 和 BSD 的返回值是否一致?

我可以确认从 10.7.4 开始,它在 Linux 和 OS X 上是一致的(具体来说,它是 -1、0 或 +1)。我对 Windows 一无所知,但我敢打赌微软人使用 -2 和 +3 只是为了破解代码:P

另外,我还要指出,您完全误解了代码的作用。

我发现这段代码(取自这个问题)依赖于 strcmp 的值,而不是 -1、0 和 1(它使用 qsort 中的返回值)。对我来说,这是一种糟糕的风格,并且取决于未记录的功能。

不,它实际上没有。C 标准库的设计考虑了一致性和易用性。也就是说,qsort()需要的是它的比较器函数返回负数或正数或零 - 正是strcmp()保证要做的事情。所以这不是“糟糕的风格”,它是完全符合标准的代码,不依赖于未记录的特性。

于 2012-11-26T19:44:48.570 回答
4

在 C99 标准中,§7.21.4.2strcmp功能

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

重点补充。

这意味着标准不保证-1,01; 它可能因操作系统而异。

w您获得的价值是和hwhich is之间的差异15

在你的情况下,hello这就是为什么返回-15。world'h'-'w' = -15 < 0strcmp

于 2012-11-26T19:45:44.997 回答
4

• 除了小于、大于或等于零之外,C 标准中是否有定义返回值的内容?如果不是,标准实现是做什么的?

不,正如您自己提到的手册页所说less than, equal to, or greater than zero的那样,标准也是如此。

• Linux、Windows 和 BSD 的返回值是否一致?

不。

在带有 gcc 的 Linux(OpenSuSE 12.1,内核 3.1)上,我得到-15/15取决于 if test1or test2is first。在 Windows 7(VS 2010)上,我得到-1/ 1

基于 的松散定义strcmp(),两者都很好。


...这依赖于 strcmp 的值不是 -1、0 和 1(它使用 qsort 中的返回值)。

对您来说一个有趣的附注...如果您查看 qsort()手册页,该示例与您使用发布的贝尔代码几乎相同strcmp()。需要比较器功能的原因qsort()实际上非常适合从以下返回strcmp()

如果认为第一个参数分别小于、等于或大于第二个参数,则比较函数必须返回小于、等于或大于零的整数。

于 2012-11-26T19:53:07.913 回答
1

页面中:

strcmp() 函数将 s1 指向的字符串与 s2 指向的字符串进行比较。非零返回值的符号由被比较的字符串中不同的第一对字节(均解释为类型无符号字符)的值之间的差异符号确定。

FreeBSD中strcmp的实现。

#include <string.h>

/*
 * Compare strings.
 */
int
strcmp(s1, s2)
    register const char *s1, *s2;
{
    while (*s1 == *s2++)
        if (*s1++ == 0)
            return (0);
    return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}
于 2012-11-26T20:06:42.837 回答
1

实际上, 的返回值strcmp很可能是第一个不同位置的字节值之间的差异,这仅仅是因为返回这个差异比执行额外的条件分支将其转换为 -1 或 1 更有效. 不幸的是,已知一些损坏的软件会假设结果适合 8 位,从而导致严重的漏洞。简而言之,除了结果的符号之外,你不应该使用任何东西。

有关这些问题的详细信息,请阅读我上面链接的文章:

https://communities.coverity.com/blogs/security/2012/07/19/more-defects-like-the-mysql-memcmp-vulnerability

于 2012-11-26T19:56:02.170 回答
0

从手册页:

返回值 如果 s1(或其前 n 个字节)分别小于、匹配或大于,则 strcmp() 和 strncmp() 函数返回一个小于、等于或大于零的整数比s2。

它只指定它大于或小于 0,没有说明具体值,我想这些是特定于实现的。

符合 SVr4、4.3BSD、C89、C99。这说明它包含在哪些标准中。该函数必须存在并按照指定的方式运行,但规范没有说明实际返回的值,因此您不能依赖它们。

于 2012-11-26T19:46:00.630 回答
0

C 标准中没有任何内容涉及返回的值strcmp()(即,除了该值的符号):

7.21.4.2 strcmp 函数

概要

#include <string.h>
int strcmp(const char *s1, const char *s2);

描述

strcmp 函数将 s1 指向的字符串与 s2 指向的字符串进行比较。

退货

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

因此很明显,使用除了返回值的符号之外的任何东西都是不好的做法。

于 2012-11-26T19:46:11.720 回答