V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
herozem
V2EX  ›  C

C 语言中"=="的用法的几个问题?

  •  
  •   herozem · 2015-04-02 09:51:28 +08:00 · 1834 次点击
    这是一个创建于 3310 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先看测试用例:

    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
      char *s = "hello";
      char *str = "hello";
    
      printf("compare pointers: ");
      s == str ? printf("y") : printf("n"); #(1)
      printf("\ncompare arguments: ");
      argv[1] == argv[2] ? printf("y") : printf("n"); #(2)
      printf("\nuse strcmp :");
      strcmp(&argv[1], &argv[2]) ? printf("y") : printf("n"); #(3)
    
      return 0;
    }
    

    运行结果:

    $ ./a.out tmp tmp
    compare pointers: y
    compare arguments: n
    use strcmp :y
    

    确切的来说是想解决一些关于C和内存知识的问题:

    在代码中, (1)比较的两个字符串, s和str在内存中是不同的指向char的指针, 但是他们指向的内容实际上是同一处?

    (2)中比较的内容结果是不相等, "=="号比较的是所给参数的内存地址吗?
    (3)的输出结果为y, 所以strcmp比较的是指针所指向的内容?

    第 1 条附言  ·  2015-04-02 10:39:48 +08:00
    顺便希望大家能够推荐一些关于C和内存的书?我对这一块不熟悉
    30 条回复    2015-04-03 00:23:24 +08:00
    Andiry
        1
    Andiry  
       2015-04-02 10:00:00 +08:00
    1) s 和 str是常量指针,指向同一个地址,所以s == str
    2) Yes
    3) Yes
    zhicheng
        2
    zhicheng  
       2015-04-02 10:01:01 +08:00 via Android
    1,是
    2,是
    3,是
    herozem
        3
    herozem  
    OP
       2015-04-02 10:03:06 +08:00
    g5tf87
        4
    g5tf87  
       2015-04-02 10:03:08 +08:00   ❤️ 2
    (1)里两个hello被编译在全局数据区,应该是被编译器优化为同一个地址,所以s和str两个指针指向的内容是一样的,输出为y。
    (2)里面两个参数由于函数调用,其内容先后被存入栈上,所以argv[1]和arg[2]也是指针,指向的内容是不一样的,输出为n。
    (3)通过字符串比较函数,比较字符串的内容,argv[1]和arg[2]指向的内容是一样的,所以输出为y。

    一点粗浅见解,如有错误,希望高手指导交流~~~
    wartime
        5
    wartime  
       2015-04-02 10:13:59 +08:00
    1. s 和 str 指向同一字符串常量, 地址值相等 (编译时确定);
    2. 命令行参数不同,内存地址不同;
    3. strcmp 比较两块内存里从第一个字节开始,到值为'\0'结束的字符串是否相等, 有可能溢出;

    如果定义成:
    char s[] = "hello";
    char str[] = "hello";
    s != str, 此时s和str会被分配size为strlen("hello") + 1的新内存地址。
    liuhaotian
        6
    liuhaotian  
       2015-04-02 10:19:54 +08:00   ❤️ 1
    是的。比较的是指向内容。
    The C library function int strcmp(const char *str1, const char *str2) compares the string pointed to by str1 to the string pointed to by str2.

    顺便问一下 markdown这个代码高亮是怎么做到的?
    herozem
        7
    herozem  
    OP
       2015-04-02 10:28:49 +08:00
    @liuhaotian 三个反单引号(数字键1左边那个), 后接bash、c、java之类的, 代码完以后另起一行再接三个反单引号

    ```bash
    ```bash
    #不知道嵌套会被解析成什么样子?
    ```
    ```
    mcone
        8
    mcone  
       2015-04-02 10:32:11 +08:00   ❤️ 1
    如果我没记错的话,你在(1)里面的这种比较是很危险的,不同编译器在不同优化等级下面输出的结果很可能不一样(undefined behavior?)

    好久没用过这个了,如有错误望楼下指出!
    herozem
        9
    herozem  
    OP
       2015-04-02 10:34:57 +08:00
    @wartime 我试了一下,对于

    ```c
    char s1[] = "hello";
    char s2[] = "hello";
    ```

    无论是使用s1 == s2 还是 strcmp(s1, s2) 结果都是n, 这其中的原因是?
    herozem
        10
    herozem  
    OP
       2015-04-02 10:38:07 +08:00
    @herozem 不过回复好像不支持Markdown, 或者是我打开方式不正确 :(
    herozem
        11
    herozem  
    OP
       2015-04-02 10:38:54 +08:00
    @mcone 这个我不太清楚, 不知道有没有相关的讲解的书籍或资料
    bugeye
        12
    bugeye  
       2015-04-02 10:44:38 +08:00
    用gcc -S xxx.c 生成汇编,然后看汇编就明白了
    $ cat test.s
    .file "test.c"
    .section .rodata
    .LC0:
    .string "hello"
    .LC1:
    .string "compare pointers: "
    .LC2:
    .string "y"
    .LC3:
    .string "n"
    .LC4:
    .string "\ncompare arguments: "
    .LC5:
    .string "\nuse strcmp :"
    .text
    .globl main
    .type main, @function
    main:

    看吧,只有一个"hello",所以两个指针的内容是一样的。但这种比较方法是危险的。如果生成的汇编很傻,那么结果就变了。
    herozem
        13
    herozem  
    OP
       2015-04-02 10:49:56 +08:00
    @bugeye 不懂汇编, 没想到可以这样看 :(
    walleL
        14
    walleL  
       2015-04-02 11:04:37 +08:00
    strcmp(&argv[1], &argv[2]) ? printf("y") : printf("n");

    大家都没发现这一行有问题吗?
    1. argv[1] 已经是指向第一个参数字符串的指针了,&argv[1] 是干嘛呢
    2. strcmp() 的返回值为0时才表示相等啊

    所以这样才对吧:
    strcmp(argv[1], argv[2]) == 0 ? printf("y") : printf("n");
    walleL
        15
    walleL  
       2015-04-02 11:06:38 +08:00
    @herozem 所以9楼的问题也是 strcmp() 返回值判断的原因吧
    hualuogeng
        16
    hualuogeng  
       2015-04-02 11:10:27 +08:00
    @herozem 请注意strcmp在字符串相等时,返回值是0,所以你用strcmp作为条件表达式的条件时,结果和你要的是相反的。
    原文中的3,之所以相等,是因为还是比较的指针本身的值,因为不相等,所以才printf("y")
    这也就能够解释你在9楼的疑问了。
    hualuogeng
        17
    hualuogeng  
       2015-04-02 11:11:54 +08:00
    上一条回复中 "原文中的3,之所以相等" 应表述为”原文中的3,之所以输出y"
    herozem
        18
    herozem  
    OP
       2015-04-02 11:12:12 +08:00
    @walleL :) thank you so much! &argv[1]确实是不对的
    herozem
        19
    herozem  
    OP
       2015-04-02 11:13:34 +08:00
    @hualuogeng 嗯, 是这样的, 谢谢
    hualuogeng
        20
    hualuogeng  
       2015-04-02 11:18:36 +08:00
    @walleL 你也发现这个问题了。

    @herozem 另外,关于C的内存和指针,我记得有一本《C缺陷和陷阱》还不错。还有《专家编程》《C和指针》也不错
    bugeye
        21
    bugeye  
       2015-04-02 11:28:34 +08:00
    @herozem 我觉得如果你读过汇编,就知道C语言实质上是一种可以跨平台的高级宏汇编。所以想搞清楚这些底层的问题,最好是去学汇编。

    但是。。。。。按软件业的现状看,还是把时间花在能快速原型,能快点做项目的语言为佳。就算用C语言也没必要搞清楚这些东西,只要记得比较字符串strcmp是正道就行。没必要浪费时间在这些底层细节上。这些细节要想100%搞清楚,得学计算机组成原理了。
    herozem
        22
    herozem  
    OP
       2015-04-02 11:31:33 +08:00
    @bugeye 是啊。。所以我觉得到C语言不能再往下了(汇编什么的), 虽然说越往下学对计算机理解的越清楚。。。
    hualuogeng
        23
    hualuogeng  
       2015-04-02 11:37:00 +08:00
    @herozem @bugeye 看你用C语言完成什么样的工作了,如果是偏底层的,了解汇编是有必要的。而如果不是,大多数时候C都不是首选。
    @herozem 刚才说的三本书中,学习内存和指针,首选《专家编程》吧。
    jemyzhang
        24
    jemyzhang  
       2015-04-02 11:46:04 +08:00
    编译优化的关系, 优化后s和str被指向同一个地址, 所以s == str成立
    ZyZyZzz
        25
    ZyZyZzz  
       2015-04-02 12:32:43 +08:00
    @hualuogeng “原文中的3,之所以输出y,是因为还是比较的指针本身的值”
    比较的不是俩指针所在的内存地址嘛_(:з」∠)_?

    还有这里用VS2010带的编译器编出的s和str指向的地址居然不一样……
    hualuogeng
        26
    hualuogeng  
       2015-04-02 13:25:51 +08:00   ❤️ 1
    @ZyZyZzz 我们的表述不一致,实际所指是一致的,如你图中所示,实际比较的是692381和692384。

    常量的编译优化是编译器实现相关的,标准上没有规定,所以总是认为s和str指向相同的内存的想法是个坑。如你所说,VS2010就和GCC实现不一样。
    21grams
        27
    21grams  
       2015-04-02 14:13:36 +08:00
    第一个是编译器优化的,不能认为永远都成立。
    xieyudi1990
        28
    xieyudi1990  
       2015-04-02 18:26:14 +08:00 via iPhone
    @Andiry s 和 str 都是变量.
    linux40
        29
    linux40  
       2015-04-02 20:01:47 +08:00
    char *str = "hello"是不好的习惯。。。至于函数有返回值的,看书吧。。。
    chisj
        30
    chisj  
       2015-04-03 00:23:24 +08:00
    《C和指针》,《C陷进和缺陷》,《C专家编程》,但是这些都不如你撸几个实际项目学的东西来得靠谱。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5436 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 06:47 · PVG 14:47 · LAX 23:47 · JFK 02:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.