将字符串作为指针或文字传递时,strcmp()返回值不一致

Ahm*_*zan 32 c c++ linux strcmp

strcmp当我注意到这一点时,我正在玩,这里是代码:

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

int main(){

    //passing strings directly
    printf("%d\n", strcmp("ahmad", "fatema"));

    //passing strings as pointers 
    char *a= "ahmad";
    char *b= "fatema";
    printf("%d\n",strcmp(a,b));

    return 0;

}
Run Code Online (Sandbox Code Playgroud)

输出是:

-1
-5
Run Code Online (Sandbox Code Playgroud)

不应该strcmp一样吗?为什么,我给我传递一个字符串作为不同的值"ahmad"或作为char* a = "ahmad".将值传递给函数时,它们是否在其堆栈中分配?

Sha*_*our 46

您很可能会看到编译器优化的结果.如果我们在godbolt上使用gcc测试代码,使用-O0优化级别,我们可以看到它没有调用的第一种情况strcmp:

movl    $-1, %esi   #,
movl    $.LC0, %edi #,
movl    $0, %eax    #,
call    printf  #
Run Code Online (Sandbox Code Playgroud)

由于你使用常量作为strcmp的参数,编译器能够执行常量折叠并在编译时调用编译器内在函数并生成-1then,而不必strcmp在运行时调用,这在标准库中实现并且将具有不同的实现然后可能更简单的编译时间strcmp.

在第二种情况下,它确实生成一个调用strcmp:

call    strcmp  #
movl    %eax, %esi  # D.2047,
movl    $.LC0, %edi #,
movl    $0, %eax    #,
call    printf  #
Run Code Online (Sandbox Code Playgroud)

这是与事实相符的gcc有STRCMP一个内置的,这是什么gcc在常量折叠期间使用的内容.

如果我们使用-O1优化级别或更高级别 进一步测试gcc能够折叠两种情况,结果将-1适用于两种情况:

movl    $-1, %esi   #,
movl    $.LC0, %edi #,
xorl    %eax, %eax  #
call    printf  #
movl    $-1, %esi   #,
movl    $.LC0, %edi #,
xorl    %eax, %eax  #
call    printf  #
Run Code Online (Sandbox Code Playgroud)

启用了更多优化选项后,优化器能够确定ab指向编译时已知的常量,并且还可以在编译期间计算strcmp此情况的结果.

我们可以gcc通过使用-fno-builtin标志构建并观察调用来确认是使用内置函数strcmp将为所有情况生成.

clang略有不同之处在于它根本不会折叠-O0但会折叠-O1两者之间.

注意,任何负面结果都是完全一致的,我们可以通过参考草案C99标准部分看到7.21.4.2strcmp函数说明(强调我的):

int strcmp(const char *s1, const char *s2);
Run Code Online (Sandbox Code Playgroud)

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

technosurus指出,strcmp指定将字符串视为由无符号字符组成,这在C99中有所7.21.1说明:

对于本子条款中的所有函数,每个字符都应解释为它具有unsigned char类型(因此每个可能的对象表示都是有效的并且具有不同的值).

  • @davmac,似乎OP想知道为什么值不同(即使它们都是负数) (11认同)
  • @asimes我的观点是,这只是为什么它们不同的解释的一部分.或者,如果您愿意,可以解释为什么它们可能不同(请记住,不同的编译器,平台等可能会产生不同的结果).但是这个问题意味着OP不理解为什么它们可以不同,并且假设数字结果对于相同的输入字符串必须始终相同是错误的. (3认同)

dav*_*mac 13

我想你相信回归的价值 strcmp应该以某种方式依赖于以函数规范未定义的方式传递给它的输入字符串.这是不正确的.例如,参见POSIX定义:

http://pubs.opengroup.org/onlinepubs/009695399/functions/strcmp.html

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

这正是你所看到的.实现不需要对确切的返回值做出任何保证- 只有在适当的时候小于零,等于零或大于零.

  • @iharob:它不是"随机的",在第二种情况下,它是'f' - 'a'的结果,但这本身就是特定的`strcmp()`的结果(尽管我怀疑实现的不同之处)尊重).第一个结果由Shafic的答案解释,并且依赖于编译器(或编译器选项).无论哪种方式,您都不能依赖于函数标准规范所保证的任何结果. (8认同)
  • 所以它返回一个随机的负数呢?我认为它应该是确定性的,并且应该对观察到的行为进行解释. (3认同)

归档时间:

查看次数:

1852 次

最近记录:

10 年,10 月 前