当我注意到这一点时,我正在玩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"
传递时,为什么给予不同的值。将值传递给函数时,它们是否在其堆栈中分配?
答案 0 :(得分:46)
您很可能会看到编译器优化的结果。如果我们test the code using gcc on godbolt,-O0
优化级别,我们可以看到第一种情况,它不会调用strcmp
:
movl $-1, %esi #,
movl $.LC0, %edi #,
movl $0, %eax #,
call printf #
由于您使用常量作为strcmp的参数,编译器能够执行constant folding并在编译时调用compiler intrinsic并生成-1
,而不是必须在运行时调用strcmp
,这在标准库中实现,并且具有不同的实现,然后可能更简单的编译时间strcmp
。
在第二种情况下,它会生成对strcmp
的调用:
call strcmp #
movl %eax, %esi # D.2047,
movl $.LC0, %edi #,
movl $0, %eax #,
call printf #
这与gcc has a builtin for strcmp这一事实是一致的,test using -O1
optimization level or greater是gcc
在常量折叠过程中将使用的事实。
如果我们进一步-fno-builtin flag gcc
能够折叠这两种情况,那么两种情况的结果都是-1
:
movl $-1, %esi #,
movl $.LC0, %edi #,
xorl %eax, %eax #
call printf #
movl $-1, %esi #,
movl $.LC0, %edi #,
xorl %eax, %eax #
call printf #
启用了更多优化选项后,优化器能够确定a
和b
指向编译时已知的常量,并且还可以为此计算strcmp
的结果在编译期间也是如此。
我们可以通过使用{{3}}进行构建来确认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 组成,这在7.21.1
下的C99中有所说明:
对于本子条款中的所有功能,每个字符应为 解释为它有类型unsigned char(因此每个 可能的对象表示是有效的,并且具有不同的值。)
答案 1 :(得分:13)
我认为您认为strcmp
返回的值应该以某种方式依赖于传递给它的输入字符串,而这种输入字符串不是由函数规范定义的。这不正确。例如,参见POSIX定义:
http://pubs.opengroup.org/onlinepubs/009695399/functions/strcmp.html
完成后,如果s1指向的字符串分别大于,等于或小于s2指向的字符串,strcmp()将返回大于,等于或小于0的整数。
这正是你所看到的。该实现不需要对精确返回值做任何保证 - 只有在适当时小于零,等于零或大于零。