strcmp输出的谜团 - strcmp如何比较字符串?

3

我想知道为什么在同一个函数中多次使用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?这是编译器在起作用吗?如果是,它到底做了什么优化?

2
查看生成的机器代码,了解它的真正作用以及编译器如何将您的源代码转换。 - Some programmer dude
4
除非返回值为0,否则您不必关心它返回的确切值;只需要知道它是小于、等于还是大于0即可。 - Shawn
1
如果您将这些文字面值分配给指针(而不是char数组),则结果与char数组的情况相同,即char* c="aa", *d = "ag";将产生相同的-6 - Duck Dodgers
1
@Shawn:C标准只规定了结果的符号,并不意味着您不应该关心其大小。遵守C标准只是软件工程的一小部分,好奇心是促进学习编译器工作原理、深入理解语义等方面的重要动力。关注和探究是有益且有价值的,因为所获得的知识可以帮助编写更优化、更少出错的代码。知识是宝贵的,人们应该珍惜。 - Eric Postpischil
2
@EricPostpischil,然而,好奇了解系统如何工作的危险在于您可能会探索并利用仅适用于您的系统的细节,这些细节在其他系统上不会产生相同的结果。我认为重要的是标准应该发生的事情。只要您知道这一点,就可以尽情探索不同系统如何实现它,但如果您不知道,您有可能最终处于未定义行为的错误一侧。 - Tim Randall
显示剩余7条评论
3个回答

6

C标准指出了关于strcmp的返回值:

第7.24.4.2节:

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,生成了对strcmpprintf的调用。然而,在第二种情况下,字符串常量被传递给两者。编译器看到这一点并自动生成结果,优化掉了实际的strcmp调用,并将硬编码值-1传递给printf

5

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

strcmp()函数比较两个字符串s1和s2。如果s1小于s2,则返回一个负整数;如果s1等于s2,则返回0;如果s1大于s2,则返回一个正整数。

strcmp函数只承诺对上述比较返回负值,实际返回的值未指定。

可能的情况是,在strcmp("aa","ag")中编译器知道结果为负值,并将其优化为-1


编译器知道结果是负数,并将其优化为-1。这种优化的可能用处是什么? - Sourav Ghosh
@SouravGhosh - 经过优化,编译器仍然遵循C标准,不需要调用strcmp函数。 - Rishikesh Raje
@RishikeshRaje 好的,我本来不打算把那个放在评论里 - 你能否把它加到答案中呢? - Sourav Ghosh
@SouravGhosh - 我认为任何优化的价值和用处都是众所周知的。代码更小,运行时间更好等。 - Rishikesh Raje

1
C标准仅保证strcmp的返回值符号表示两个字符串之间的关系,如果两个字符串相等则返回0。通常情况下,返回第一个不同字符处的ASCII码差值是一种实现方式,但并非必须。如果编译器能够立即确定strcmp的结果,则可能直接添加-110,而不是调用函数。解决方法是不要编写依赖于特定strcmp实现的代码,只信任返回值的符号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接