【问题标题】:Mystery with strcmp output - How strcmp actually compares the strings?strcmp 输出之谜 - strcmp 如何实际比较字符串?
【发布时间】:2019-07-09 16:37:02
【问题描述】:

我想知道为什么strcmp() 在同一个函数中多次使用会返回不同的值。下面是程序。第一种情况我知道它为什么打印-6。但是在第二种情况下,为什么它打印-1?

#include<stdio.h>
#include<string.h>
int main()
{
    char a[10] = "aa";
    char b[10] = "ag";
    printf("%d\n",strcmp(a, b));
    printf("%d\n",strcmp("aa","ag"));
    return 0;
}

它产生的输出如下

[sxxxx@bhlingxxx test]$ gcc -Wall t51.c
[sxxxx@bhlingxxx test]$ ./a.out
    -6
    -1

为什么第二个strcmp()的输出是-1?是编译器在这里玩吗?如果是这样,它的具体优化是什么?

【问题讨论】:

  • 看看生成的机器代码,看看它到底做了什么,以及编译器是如何翻译你的源代码的。
  • 你不应该关心它返回的确切值(除非它是 0);仅当它小于、等于或大于 0 时。
  • 如果将这些文字分配给指针(而不是 char 数组),结果将与 char 数组的情况相同,即char* c="aa", *d = "ag";,将产生相同的-6。
  • @Shawn:C 标准仅指定结果的符号这一事实并不意味着您不应该关心数量级。遵守 C 标准只是软件工程的一小部分,而好奇心是一个很大的动力,有助于学习编译器的工作原理,加深对语义的理解等等。关心和询问是好的和有价值的,因为获得的知识可以导致编写更好优化的代码,不太可能包含错误等等。知识是宝贵的,人们应该关心。
  • @EricPostpischil 然而,对您的系统究竟是如何工作的好奇可能会导致您探索和利用实际上特定于您的系统的小细节的危险,而这些细节并不在其他系统上产生相同的结果。我认为,重要的是标准所说的应该发生的事情。只要您知道这一点,您就可以探索不同的系统是如何实现它的,但如果您不这样做,您最终可能会陷入未定义行为的错误方面。

标签: c string strcmp


【解决方案1】:

C standard 对strcmp 的返回值表示如下:

第 7.24.4.2p3 节:

strcmp 函数返回一个大于、等于、 或小于零,因此 s1 指向的字符串是 大于、等于或小于 s2 所指向的字符串

只要结果符合该描述,它就符合 C 标准。这意味着编译器可以执行优化以适应该定义。

如果我们看一下汇编代码:

.loc 1 7 0
leaq    -32(%rbp), %rdx
leaq    -48(%rbp), %rax
movq    %rdx, %rsi
movq    %rax, %rdi
call    strcmp
movl    %eax, %esi
movl    $.LC0, %edi
movl    $0, %eax
call    printf
.loc 1 8 0
movl    $-1, %esi      # result of strcmp is precomputed!
movl    $.LC0, %edi
movl    $0, %eax
call    printf

在第一种情况下,数组被传递给strcmp 以调用strcmp 并生成对printf 的调用。然而,在第二种情况下,字符串常量被传递给两者。编译器看到这一点并自己生成结果,优化对strcmp 的实际调用,并将硬编码值-1 传递给printf。

【讨论】:

    【解决方案2】:

    来自https://linux.die.net/man/3/strcmp

    strcmp() 函数比较两个字符串 s1 和 s2。如果 s1 分别小于、匹配或大于 s2,则返回一个小于、等于或大于零的整数。

    strcmp 函数只承诺为上面给出的比较返回负值。未指定实际返回的值。

    可能发生的情况是,对于strcmp("aa","ag"),编译器知道结果是否定的,并将其优化为-1

    【讨论】:

    • compiler knows the result is negative and optimises it to -1..这种优化可能有什么用处?
    • @SouravGhosh - 经过优化,编译器仍然遵循 C 标准,不需要调用 strcmp
    • @RishikeshRaje 好的,我不打算在 cmets 中使用它 - 你能把它添加到答案本身吗?
    • @SouravGhosh - 我认为任何优化的价值和有用性都是众所周知的。更小的代码,更好的运行时间等等。
    【解决方案3】:

    C 标准对strcmp 唯一保证的是,返回值的符号将指示不等式的方向(如果存在 1,则表示不等式的方向),或者如果字符串完全相等,则表示不等式的方向。

    虽然首先返回 chars 的数值之间的差异是一种相当常见的实现方式,但这不是必需的。如果编译器可以查看字符串常量并立即知道strcmp 的结果是什么,它可能会在其位置添加一个平面-1、1 或0,而不是通过实际的努力调用函数。

    解决方案是不要编写依赖于strcmp 特定实现的代码,无论它多么常见。只相信返回值的符号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 2016-07-21
      相关资源
      最近更新 更多