一尘不染

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

linux

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;

}

输出为:

-1
-5

应该不strcmp一样吗?为什么当我传递字符串as "ahmad"或as 时,我得到不同的值呢char* a = "ahmad"?当您将值传递给函数时,它们会在其堆栈中分配吗?


阅读 464

收藏
2020-06-03

共1个答案

一尘不染

您最有可能看到编译器优化的结果。如果我们使用上godbolt
GCC的测试代码
,以-O0优化级别,我们可以看到它不调用第一种情况strcmp

movl    $-1, %esi   #,
movl    $.LC0, %edi #,
movl    $0, %eax    #,
call    printf  #

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

在第二种情况下,它的确产生了对的调用strcmp

call    strcmp  #
movl    %eax, %esi  # D.2047,
movl    $.LC0, %edi #,
movl    $0, %eax    #,
call    printf  #

这与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  #

通过启用更多优化选项,优化器不仅可以确定ab指向编译时已知的常量,还可以在编译时strcmp针对这种情况计算结果。

我们可以gcc通过使用-fno-
builtin标志
进行构建并观察strcmp在所有情况下都会生成对的调用,从而确认正在使用内置函数。

clang稍有不同,因为它不会完全折叠,-O0但会同时折叠在-O1上面和上面。

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

int strcmp(const char *s1, const char *s2);

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

technosurus指出,将strcmp其指定为将字符串视为由 未签名的char 组成,这在C99中已作如下介绍7.21.1

对于本节中的所有功能,每个字符都应被解释为具有无符号字符类型(因此,每个可能的对象表示形式都是有效的并且具有不同的值)。

2020-06-03