当前位置: 首页 > 面试题库 >

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

封俊艾
2023-03-14
问题内容

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"?当您将值传递给函数时,它们会在其堆栈中分配吗?


问题答案:

您最有可能看到编译器优化的结果。如果我们使用上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

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



 类似资料:
  • 主要内容:到底使用字符数组还是字符串常量C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中,这在《 C语言字符数组和字符串》中已经进行了详细讲解,这里不妨再来演示一下: 运行结果: https://www.xnip.cn https://www.xnip.cn 字符数组归根结底还是一个数组,上节讲到的关于 指针和数组的规则同样也适用于字符数组。更改上面的代码,使用指针的方式来输出字符串: 运行结果: https://ww

  • 问题内容: 如何将类型中的字符串指针的引用值设置为空字符串?考虑以下示例: 我尝试了和运算符的所有组合都无济于事: 显然其中一些很愚蠢,但我没有发现尝试的危害。我也尝试使用和: 这会导致编译错误 恐慌:反映:使用不可寻址的值reflect.Value.SetString 我假设这是因为Go中的字符串是不可变的? 问题答案: 字符串文字不可寻址。 取包含空字符串的变量的地址: 或使用新的:

  • 我有一个语法,需要在输入流的任何一点处理以‘{*开始,以*}结束’的注释。此外,它还需要处理以“{”开头,后接“$"或与标识符,最后以”}“结尾的模板标记,并将其他内容作为文本传递。 实现这一点的唯一方法似乎是将任何不是注释或标记的东西作为单个字符传递回解析器,并让解析器构建字符串。这是非常低效的,因为解析器必须为它接收到的每个字符构建一个节点,然后我必须遍历这些节点,从这些节点构建一个字符串。如

  • 我必须交换作为指针传递到函数中的两个字符字符串:bool swap_strings(char*string1,char*string2),如果两个字符串的长度不相同,则返回false;否则,如果交换成功,则返回true; 我如何才能意识到这一点?为什么这是不正确的:

  • 问题内容: 我想将字符串切片转换为指向字符串的指针切片 %!p(string = a)=>字符串 %!p(string = b)=>字符串 %!p(string = c)=>字符串 [0xc42000e1d0 0xc42000e1d0 0xc42000e1d0] 据我了解, 我的变量似乎是一个字符串,而不是指向字符串的指针。 因此应从迭代时复制。 显然我不正确,因为地址仍然相同。如果值不是指针,该

  • 从java中字符串的值创建对现有对象的引用 在我的项目中,有很多按钮(目前大约70个);每个按钮都会在数据库的jlabel中提出一个问题。现在,根据用户的选择,每个按钮(swings的jButton)将被分配颜色,这取决于用户是否想查看问题,或者他是否标记了问题的答案。 一种方法是为每个jbutton的actionperformed编码,并在每个jbutton中使用if-else来获得确切的颜色,