C 语言中"=="的用法的几个问题? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
herozem
V2EX    C

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

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

    先看测试用例:

    #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     Solana     2626 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 09:22 PVG 17:22 LAX 02:22 JFK 05:22
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86