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

为什么这段 C 代码结果是 1?

  •  
  •   KyL · 2016-03-11 23:16:29 +08:00 · 6067 次点击
    这是一个创建于 3182 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看到这么一道面试题

    #include <stdio.h>
    void main()
    {
       int a=1,b=0,c=-1,d=0;
       d=++a||++b&&++c;
       printf("d=%d", d); //output 1;
       return;
    }
    

    我不理解为什么 d 会变成 1 而不是 2 。我知道所谓“短路”,但是无论如何,最左边 d=++a 这个表达式都会被 evaluate 啊。

    #include <stdio.h>
    void main()
    {
       int a=1,b=0,c=-1,d=0;
       d=++a;
       printf("d=%d", d); //output 2
       return;
    }
    

    这个结果就得 2 。

    为什么呢?

    61 条回复    2016-03-13 14:50:29 +08:00
    stackpop
        1
    stackpop  
       2016-03-11 23:22:27 +08:00
    运算符优先级
    c0nnax
        2
    c0nnax  
       2016-03-11 23:22:31 +08:00
    前面那个是逻辑吧
    raysonx
        3
    raysonx  
       2016-03-11 23:23:04 +08:00 via Android
    ||是邏輯運算符,返回結果只可能是 1 或 0 。
    ll0xff
        4
    ll0xff  
       2016-03-11 23:23:44 +08:00
    因为 (++a||++b&&++c )实际是个 boolean 值。
    KyL
        5
    KyL  
    OP
       2016-03-11 23:25:15 +08:00
    好吧,我明白了。
    `d=++a||++b&&++c;`的执行顺序应该是
    `d=((++a)||((++b)&&(++c)))`
    ++a = 2 直接就决定了 d="true",也就是 d=1
    ben3ai
        6
    ben3ai  
       2016-03-11 23:27:24 +08:00 via iPhone
    这个表达式中=运算符的优先级是最低的,=右边, and 优先级高于 or ,++a 为 true ,编译器应该是把逻辑真作 1 处理了
    ETiV
        7
    ETiV  
       2016-03-11 23:30:04 +08:00   ❤️ 1
    因为 "||", "&&" 被理解成了判断 true / false

    并且, 从左到右, 先遇到了 ||, 所以只要 || 左边的结果 !=0 , 就直接返回了 true.
    后面的 ++b, ++c 都没有被运算到...你自己试试看吧..
    airqj
        8
    airqj  
       2016-03-11 23:32:07 +08:00
    实际上只会算(++a)
    wenyu1001
        9
    wenyu1001  
       2016-03-11 23:36:36 +08:00
    出现这样的代码, code review 时定会被骂,幸好只是面试题。
    r00t
        10
    r00t  
       2016-03-11 23:42:10 +08:00
    我发现某些公司总是喜欢出这种面试题~优先级看好就 ok
    oplang
        11
    oplang  
       2016-03-11 23:47:10 +08:00
    8 楼说的对,算完(++a)就直接把值赋给等号左边了,没后面什么事
    neilp
        12
    neilp  
       2016-03-11 23:55:52 +08:00 via iPhone
    不要跟 js 搞混了
    theohateonion
        13
    theohateonion  
       2016-03-12 02:02:45 +08:00   ❤️ 8
    。。个人强烈反对去研究这种代码,感觉一点意义都没有。。这种代码的出现本身就是一个错误,无数的小白因为这些东西把编程看作洪水猛兽,其实真正的编程真的很美不是吗。
    Ge4Los
        14
    Ge4Los  
       2016-03-12 02:24:21 +08:00
    1. 逻辑运算符的 || 优先级高于赋值运算符 =。
    2. || 运算符的短路特性。|| 前面条件为真, 后面的条件是不需要继续运算。
    3. C 中布尔值真为 1 。
    这题涉及的内容属于 C 专有的特性。
    shiji
        15
    shiji  
       2016-03-12 02:38:32 +08:00
    @theohateonion 同强烈反对,这就像小学的奥数题,费时,麻烦,并且将来没什么卵用。 也许只会在面试这种环节出现吧,一辈子再也遇不到了。
    Valyrian
        16
    Valyrian  
       2016-03-12 02:45:21 +08:00 via iPad
    @shiji 小学奥数很开拓思维好吗
    arslion
        17
    arslion  
       2016-03-12 02:55:40 +08:00
    sensui7
        18
    sensui7  
       2016-03-12 03:56:58 +08:00
    @shiji 是一辈子根本都不会写这种代码, 这种反人类的代码, 除了能装比没有任何好处。
    yangqi
        19
    yangqi  
       2016-03-12 05:00:03 +08:00
    运算符优先级,最基本的东西,能看出一个人的基本功
    shiji
        20
    shiji  
       2016-03-12 05:08:02 +08:00
    @Valyrian 是挺好玩的,但是拿来一道题几乎没人能会做,反正我学的奥数几乎都是针对每一种题型,记忆住解题的规律,然后这一类题就都会了。等哪一天忘了那个规律或者是公式,脑子里就啥也不剩了。
    chaoerzheng
        21
    chaoerzheng  
       2016-03-12 08:33:59 +08:00
    我没算结果,写“ d=++a||++b&&++c;”的这个人是垃圾。
    ershisi
        22
    ershisi  
       2016-03-12 08:49:35 +08:00
    这个题个人认为是逻辑运算的编译阶段优先级。右侧优先于左侧。另外,这种题做完理解意思就行了。生产环境中你要是这么写代码肯定自己都想骂自己。
    chenps10
        23
    chenps10  
       2016-03-12 09:06:26 +08:00
    @ershisi 自己骂不骂自己不知道,技术上司会直接开了他吧。。。这种属于没法教的了
    kiwi95
        24
    kiwi95  
       2016-03-12 09:13:48 +08:00 via Android
    面试如果问这种题,直接拒绝回答就是了
    kiwi95
        25
    kiwi95  
       2016-03-12 09:19:57 +08:00 via Android
    哦,好像看错了,
    zwpaper
        26
    zwpaper  
       2016-03-12 09:19:57 +08:00
    @ETiV && 优先级不是比 || 高一级吗?
    jiangtao92
        27
    jiangtao92  
       2016-03-12 10:15:38 +08:00
    这个算是逻辑运算吧,不是 true 就是 false !
    matthewz
        28
    matthewz  
       2016-03-12 10:16:10 +08:00 via iPhone
    这道题还可以啊 不算是那种++++++a 的傻逼题
    wezzard
        29
    wezzard  
       2016-03-12 11:46:11 +08:00
    我會回答:「對不起我不會譚語言編程。」
    wezzard
        30
    wezzard  
       2016-03-12 11:58:02 +08:00
    看了看,這道題考的是邏輯運算以及譚語言裏面布爾到底是甚麼。
    但是在現代 C 語言編譯器裏面,這段譚語言的代碼編譯是無法通過的,因爲:
    1 )我不知道譚語言的標準,但是 C 語言的 main 函數是需要返回 int 類型的值的;
    2 )我不知道譚語言的標準,但是 xxx || xxx && xxx 這種寫法在現代 C 語言編譯器的默認警告設定下是會報警的;
    raysonx
        31
    raysonx  
       2016-03-12 12:13:11 +08:00 via Android
    @wezzard 譚語言,蛤蛤
    qian19876025
        32
    qian19876025  
       2016-03-12 12:23:07 +08:00
    劝楼主多看看书 其他的都白说 你到现在如何断句都有问题
    Testalias
        33
    Testalias  
       2016-03-12 12:51:42 +08:00
    看到 void main 就知道出处了,
    出这个面试题的应该不怎么写 C 。
    jukka
        34
    jukka  
       2016-03-12 12:55:24 +08:00
    别在这些东西上浪费生命。
    china521
        35
    china521  
       2016-03-12 13:03:35 +08:00   ❤️ 1
    @jukka 同意,如果线上产品写这样的代码,直接会被 fire 的. 也就教科书上用用
    Qiangyuan
        36
    Qiangyuan  
       2016-03-12 15:15:47 +08:00
    这题不错,考察程序基本功
    donghouhe
        37
    donghouhe  
       2016-03-12 15:19:53 +08:00 via iPad
    学习这种是能加深理解的,还是有点用的。如果你是做不出才愤怒地说没用,那就错了。如果你能轻松做出,那才有资格说。
    sagnitude
        38
    sagnitude  
       2016-03-12 15:55:27 +08:00
    虽然很多类似的题目毫无意义,但是这道题确实考察了基础
    有些题目纠结于++符号,是毫无意义的,碰到那种代码,我会在代码规范里加上“类似情况必须加括号”
    这道题说的是赋值符号,和语言基本无关,楼上几位结论下太快的可以再看几眼题目
    JJFJJ
        39
    JJFJJ  
       2016-03-12 16:02:27 +08:00
    写这样的代码,在 CodeReview 和以后维护的时候,会被人骂死的。
    为什么不加括号来解决优先级的问题呢
    syhilyhw
        40
    syhilyhw  
       2016-03-12 16:10:54 +08:00
    这个你只能怪+++++
    cuteshell
        41
    cuteshell  
       2016-03-12 16:42:52 +08:00
    @zwpaper 是同优先级的,就像“+”和“-”一样,从左向右算。
    wuhanchu
        42
    wuhanchu  
       2016-03-12 16:58:54 +08:00
    差点被你被你骗了
    先算++a||++b&&++c 再赋值。。哎呀 这个问题 真是折磨人
    vagarlee
        43
    vagarlee  
       2016-03-12 17:19:42 +08:00
    d=(++a||++b&&++c)
    ++a||++b&&++c 的值返回的是 1 因为||
    aksoft
        44
    aksoft  
       2016-03-12 17:22:04 +08:00
    码农和程序员的区别。
    kingoldlucky
        45
    kingoldlucky  
       2016-03-12 17:59:01 +08:00
    这道题真的很简单..真的很简单..
    一眼扫过去就知道结果不是 0 就是 1
    kingoldlucky
        46
    kingoldlucky  
       2016-03-12 18:00:16 +08:00
    而且看完第一个++a|| 到这里了就知道结果一定为 1
    只要有一个为真,表达式就为真
    kingoldlucky
        47
    kingoldlucky  
       2016-03-12 18:02:27 +08:00
    楼上那么多反对这道题的,C 语言真的是弱爆了,校招怎么找到工作啊.
    Balthild
        48
    Balthild  
       2016-03-12 18:26:26 +08:00
    @wezzard 不是說 C99 裡面規定了 main 的類型如果是 int ,不寫返回值則默認返回 0 嗎?
    Wonicon
        49
    Wonicon  
       2016-03-12 18:39:24 +08:00
    @Balthild 问题是返回类型是 void ......
    zwpaper
        50
    zwpaper  
       2016-03-12 18:58:16 +08:00
    zwpaper
        51
    zwpaper  
       2016-03-12 19:12:58 +08:00
    @kingoldlucky 请教一下,我从维基百科看到的运算符优先级中 && 是比 || 高一级的,那在一个语句里同时出现,为什么不处理 &&?
    我知道 || 的短路效果,但是按优先级来看,难道不是应该先处理 && 吗?
    从短路效果这点来看,无论什么运算,只要 || 前面为真,放在 || 之后都不运算,那 || 优先级的意义在哪?尤其是还专门分别给 && 和 || 定义 13 , 14 两个优先级。
    https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
    Viztor
        52
    Viztor  
       2016-03-12 19:24:11 +08:00   ❤️ 1
    这道题还可以啊。

    @zwpaper
    优先级的意思是:
    A || B && C == A || (B && C)
    != (A || B) && C
    kingoldlucky
        53
    kingoldlucky  
       2016-03-12 19:36:49 +08:00
    @zwpaper 这道题 || 右边的所有结果对最后的 0 1 不构成影响
    zwpaper
        54
    zwpaper  
       2016-03-12 19:47:38 +08:00
    @Viztor 明白了,指的是结合优先级,而不是运算优先级,感谢!
    nicevar
        55
    nicevar  
       2016-03-12 21:05:22 +08:00
    这种问题看汇编代码最清晰,哪能记得住那么多优先级
    bp0
        56
    bp0  
       2016-03-13 00:03:10 +08:00   ❤️ 1
    @KyL 这道题考的是前置++的运算时间,以及||和&&优先级的关系。

    @zwpaper 不是不计算,而是还没开始计算就被跳过去了。如果优先级反过来,结果就是 0 了。

    正因为&&的优先级高,所以表达式就像 @Viztor 说的是 ++A || (++B && ++C) ,算完++A 后,因为结果是 2 ,所以跳到给 d 赋值了(汇编级别而言)。

    如果是||的优先级高,那么表达式就是 (++A || ++B) &&++C 。当++A 算完以后,不用算++B 。但是还要算++C 的,而 C 的初值是-1 。++C 的意思是先++,然后再&&。而-1 自增后是 0 。

    所以,如果||的优先级高,那么 d 的值应该是 0 。
    cuteshell
        57
    cuteshell  
       2016-03-13 12:23:22 +08:00
    @zwpaper 是我弄错了,如果是同优先级++a||++b&&++c 的结果就是 false 了,应该是++a||(++b&&++c)就对了。
    KyL
        58
    KyL  
    OP
       2016-03-13 13:46:09 +08:00
    @theohateonion 谁说不是呢。这种代码老老实实用括号括起来就什么问题都没有。可是谁让很多公司就爱出这中面试题呢?
    theohateonion
        59
    theohateonion  
       2016-03-13 14:47:55 +08:00
    @KyL 我觉得公司这么考考虑的应该是看你对一门语言掌握的深度如何,其实这样还是有道理的,但是现在的情况是,作为一名大四狗,我在四年的学习中看到很多老师和教材也把这些题作为了教学的重点,导致很多学生失去了编程的兴趣,令人扼腕
    theohateonion
        60
    theohateonion  
       2016-03-13 14:48:39 +08:00
    @KyL 也可能是我们学校教学方面还存在着问题吧(西安某 985 )
    yuchting
        61
    yuchting  
       2016-03-13 14:50:29 +08:00
    4 年多没碰 C 了,不过看了一下,感觉等号右边是个 bool 式,那么赋值不是 1 就是 0 ,到不了其他情况去的吧?这个是编译器干的,再高级一点的语言,编译器直接报错的。

    出这个题的目的应该是判断“++”在左边或右边的情况,以及条件运算符从左到右的依次判断及运算舍弃的期基础知识。不要吐槽了。实际编程不会写成这样的,但是实际情况中的 bug 都是因为这个关系没有理清楚而导致的所谓的低级错误。

    有些戏低级错误找起来巨麻烦, 3 年重压下找到后只想自杀,后悔当年没学好。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3140 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 13:21 · PVG 21:21 · LAX 05:21 · JFK 08:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.