为什么这段 C 代码结果是 1? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
KyL
V2EX    程序员

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

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

    看到这么一道面试题

    #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
    哦,好像看错了,
    ikw
        26
    ikw  
       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:00via 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 ......
    ikw
        50
    ikw  
       2016-03-12 18:58:16 +08:00
    ikw
        51
    ikw  
       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  
    &nbs;  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 不构成影响
    ikw
        54
    ikw  
       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     Solana     927 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 22:49 PVG 06:49 LAX 15:49 JFK 18:49
    Do have faith in what you're doing.
    ubao 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