繁体   English   中英

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

[英]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"传递给我时,我被赋予不同的值。 将值传递给函数时,它们是否在其堆栈中分配?

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

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

由于你使用常量作为strcmp的参数,编译器能够执行常量折叠并在编译时调用编译器内在函数并生成-1 ,而不必在运行时调用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结果。

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

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

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

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

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM