将string作为指针或文字传递时,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; } 

输出是:

 -1 -5 

不应该strcmp工作一样吗? 为什么当我把string作为"ahmad"char* a = "ahmad"传递给我时,我会得到不同的价值。 当你将值传给一个函数时,它们被分配到它的堆栈中了吗?

Solutions Collecting From Web of "将string作为指针或文字传递时,strcmp()返回值不一致"

你很可能看到了编译器优化的结果。 如果我们使用gb在godbolt上测试代码 ,使用-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标志建立gcc来确认gcc正在使用内建函数,并且观察到所有情况都会产生对strcmp的调用。

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的整数。

这正是你所看到的。 实现并不需要对确切的返回值做任何保证 – 只有它小于零,等于零或大于零。