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

Inconsistent strcmp() return value when passing strings as pointers or as literals

当我注意到这一点时,我正在玩 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 不应该一样吗?当我将字符串作为 "ahmad"char* a = "ahmad" 传递时,为什么会得到不同的值?当您将值传递给函数时,它们是在其堆栈中分配的吗?

我认为您认为 return 由 strcmp 编辑的值应该以某种方式取决于以函数规范未定义的方式传递给它的输入字符串。这是不正确的。例如参见 [​​=21=] 定义:

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

Upon completion, strcmp() shall return an integer greater than, equal to, or less than 0, if the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2, respectively.

这正是您所看到的。实施不需要对 exact return 值做出任何保证 - 只有小于零、等于零或大于零的值才合适。

您很可能会看到编译器优化的结果。如果我们 test the code using gcc on godbolt,使用 -O0 优化级别,我们可以看到第一种情况它不会调用 strcmp:

movl    $-1, %esi   #,
movl    $.LC0, %edi #,
movl    [=10=], %eax    #,
call    printf  #

由于您在编译时使用常量作为 strcmp the compiler is able for perform constant folding and call a compiler intrinsic 的参数,然后生成 -1,而不必在 运行 时调用 strcmp在标准库中实现,并将有一个不同的实现,然后可能更简单的编译时间 strcmp.

在第二种情况下,它会生成对 strcmp:

的调用
call    strcmp  #
movl    %eax, %esi  # D.2047,
movl    $.LC0, %edi #,
movl    [=11=], %eax    #,
call    printf  #

这与 gcc has a builtin for strcmp 的事实一致,gcc 将在常量折叠期间使用。

如果我们进一步 test using -O1 optimization level or greater 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 flag 构建并观察到所有情况下都会生成对 strcmp 的调用。

clang 略有不同,它在使用 -O0 时根本不折叠,但会在 -O1 及以上折叠。

注意,任何否定结果都是完全符合的,我们可以通过转到草案 C99 标准部分看到 7.21.4.2 strcmp 函数说(强调我的 ):

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

The strcmp function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2.

technosurus 指出 strcmp 被指定为将字符串视为由 unsigned char 组成,这在 7.21.1 下的 C99 中有所介绍其中说:

For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).