这是C中strcmp()的唯一返回值吗?

时间:2014-07-29 12:19:35

标签: c string strcmp

我正在学习C,目前正在学习字符串处理。从我在哪里学习,strcmp()被定义为 -

  

这是一个比较两个字符串以查明它们是否的函数   相同或不同。两个字符串比较字符   字符,直到其中一个字符串不匹配或结束为止   到达,以先发生者为准。如果两个字符串相同,   strcmp()返回零值。如果不是,则返回数字   第一个非匹配对的ASCII值之间的差异   字符。

有一个示例程序,这就是我的问题 -

main( )
{
    char string1[ ] = "Jerry" ;
    char string2[ ] = "Ferry" ;
    int i, j, k ;
    i = strcmp ( string1, "Jerry" ) ;
    j = strcmp ( string1, string2 ) ;
    k = strcmp ( string1, "Jerry boy" ) ;
    printf ( "\n%d %d %d", i, j, k ) ;
}

我在我的Windows(64位)机器上运行Dev-C ++上的这个程序,得到了这个输出 - 0 1 -1

现在,本书将输出显示为0 4 -32,并带有此推理 -

  

在第一次调用strcmp()时,两个字符串是相同的 - “Jerry”   和“Jerry” - strcmp()返回的值为零。在第二   打电话,“杰里”的第一个字符与第一个字符不匹配   “渡轮”的字符,结果是4,这是数字   “J”的ASCII值与“F”的ASCII值之间的差异。在里面   第三次打电话到strcmp()“杰里”与“杰瑞男孩”不匹配,   因为“Jerry”末尾的空字符与   “杰里男孩”中的空白。返回的值是-32,它是值   null字符减去空格的ASCII值,即'\ 0'减去'',   等于-32。

为了确认这本书的内容,我将这段代码添加到我的程序中,只是为了验证J和F之间的ASCII差异:

printf("\n Ascii value of J is %d", 'J' );
printf("\n Ascii value of F is %d", 'F' );

然后我相应地在输出中得到了这个 -

 Ascii value of J is 74
 Ascii value of F is 70

这是根据书中所说的,然而,正如你所看到的,我得到了不同的j和k值,也就是说,当字符串不匹配时。我确实在SO上查找了类似的问题,并得到了其中的一些,但是对于不同的输出(当它返回1 and -1时)无法得到明确的答案,因此我决定提出一个新问题。

此问题here似乎有些类似,问题说明包含有关strcmp()的以下信息 -

  

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

在其中一个答案中,我遇到了this link,它记录了strcmp()的功能。它进一步说 -

  

strcmp()函数应将s1指向的字符串与   s2指向的字符串。

     

非零返回值的符号应由符号确定   第一对字节的值之间的差异(两者都有)   解释为类型unsigned char),字符串不同   比较。

     

返回值

     

完成后,strcmp()将返回一个大于等于的整数   to,或小于0,如果s1指向的字符串大于,   等于或小于s2指向的字符串。

因此,在阅读了所有这些之后,我倾向于认为无论使用何种实现/平台,strcmp()函数都应该仅用于将返回值视为三个中的一个类别(0, positive and negative),而不是依赖于返回的确切值。

我的理解是否正确?

4 个答案:

答案 0 :(得分:3)

以下是来自Apple的libc在C中的strcmp()的简单实现:

int
strcmp(const char *s1, const char *s2)
{
    for ( ; *s1 == *s2; s1++, s2++)
        if (*s1 == '\0')
            return 0;
    return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1);
}

FreeBSD的libc实现:

int
strcmp(const char *s1, const char *s2)
{
    while (*s1 == *s2++)
        if (*s1++ == '\0')
            return (0);
    return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}

以下是GNU libc的实现,它返回字符之间的区别:

int
strcmp (p1, p2)
     const char *p1;
     const char *p2;
{
  const unsigned char *s1 = (const unsigned char *) p1;
  const unsigned char *s2 = (const unsigned char *) p2;
  unsigned char c1, c2;

  do
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0')
    return c1 - c2;
    }
  while (c1 == c2);

  return c1 - c2;
}

这就是为什么我所阅读的大多数比较都是用< 0== 0> 0写的,如果它不需要知道它之间的确切差异字符串中的字符。

答案 1 :(得分:3)

  

完成后,如果s1指向的字符串分别大于,等于或小于s2指向的字符串,strcmp()将返回大于,等于或小于0的整数。

你写道:

  

因此,在阅读完所有内容之后,我倾向于认为0,1或-1是strcmp()函数唯一可能的结果。

为什么呢?确切地说,没有指定返回整数的实际值,只有它的符号。

答案 2 :(得分:3)

C语言规范是用英语编写的文档

标准化委员会的成员仔细选择他们的话,允许实施者做出自己的实施选择。

在某些硬件(或实现)上,返回任何整数(遵守规范的约束)可能比仅返回-1,0,1更快(或更简单,或更小的代码)(就像{{{ 3}})。 FWIW,dvm's answer更短,并且可以返回-1,0,1之外的整数;但它符合标准。

BTW,musl-libc's strcmp.c&amp; GCC(例如在大多数Linux系统上)strcmp函数可以在优化时处理 - 作为编译器 GNU libc - __builtin_strcmp。有时可以用一些非常有效的代码替换它。

尝试编译以下函数(在文件abc.c中)

#include <string.h>
int isabc(const char*s) { return strcmp(s, "abc"); }

启用优化并查看汇编代码。在我的Debian / Sid / x86-64上使用GCC 4.9.1,使用gcc -fverbose-asm -S -O2 abc.c进行编译我在生成的abc.s中看不到任何函数调用(但isabc可能返回除-1,0,1)。

你应该关心可移植代码,因此你不应该期望一个特定的值(只要你的供应商的strcmp服从其不精确和模糊的规范)

另请阅读builtin,这是一个相关的想法:语言规范是自愿不准确的,允许各种实现者做不同的实现选择

答案 3 :(得分:1)

0, 1, -1就像标准值,但您应该考虑这些:zero, positive, negative

在这种情况下意义:

  • Zero(0)表示字符串相等。
  • Negative(-1或任何其他)表示第一个字符串 less
  • Positive(1或任何其他)表示第一个字符串 more