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

求教: Linux 下一道 C 语言的经典面试题

  •  
  •   revotu · 2017-06-27 17:09:27 +08:00 · 2064 次点击
    这是一个创建于 2711 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果在 Linux 下使用 GCC 编译器执行下列程序,输出结果是什么?

    #include<stdio.h> int main(){ int a=5; printf("%d %d %d",a++,a++,++a); return 0; }

    原问题出处: http://www.revotu.com/advanced-c-interview-questions-and-answers.html

    求详细讨论!!!

    10 条回复    2017-09-03 08:01:19 +08:00
    xss
        1
    xss  
       2017-06-27 19:26:34 +08:00
    你需要知道的:
    1. c 语言的函数调用规则是 cdecl
    2. cdecl 调用规则参数由右向左入栈

    因此, 计算顺序由右向左, 即
    ++a
    a++
    a++

    然后你还需要知道的, gcc 的行为:
    所有具有前置自增 /减运算符位置的参数, 需要等所有前&后置运算完成之后, 才能决定.
    所有具有后置自增 /减运算符位置的参数, 一旦前面的运算符完成, 值即可决定.

    所以
    ++a => a=6 -> 决定了第二个参数为 6, 因为第二个参数之前, 再无前置运算, 且第二个参数为后置运算
    a++ => a=7 -> 决定了第一个参数为 7, 因为第一个参数之前再无前置运算, 且第一个参数为后置运算
    a++ => a=8 -> 所有运算完成, 所有具有前置运算符位置的参数, 全部等于这个值

    因此, 输出为:
    7, 6, 8

    再看个复杂的:
    printf("%d %d %d %d %d", a++, a++, a++, --a, ++a);

    从右向左:
    ++a -> 6, 前面还有前置运算, 该位置参数的值未确定
    --a -> 5, 还有前置, 该位置未确定值, 但是前一个参数是后置运算, 因此前面一个参数的值为 5
    a++ -> 6, 这个位置的参数由上一步确定, 为 5, 同时决定下面的一个 a++的值为 6
    a++ -> 7, 上一个 a++的值为 7
    a++ -> 8, 所有自增操作运算完毕, 参数位置为前置自增的值可以定了, 为 8

    因此, 输出为:
    7 6 5 8 8
    snnn
        2
    snnn  
       2017-06-27 20:02:21 +08:00
    神经病。哪凉快哪躺着去
    snnn
        3
    snnn  
       2017-06-27 20:03:41 +08:00
    @xss 你第一句话就是错的。什么是 cdecl 啊?谁规定非得照它来啊。不这么来的多了去了。
    billlee
        4
    billlee  
       2017-06-27 21:28:58 +08:00
    在未定义行为上折腾是没有意义的
    gnaggnoyil
        5
    gnaggnoyil  
       2017-06-28 06:33:29 +08:00
    按照 C99/11 标准,单个函数调用时各个参数的计算相互之间没有 sequenced before 关系,所以在这里有副作用的几条表达式直接炸成 UB.如果有谁想问 UB 的代码有什么外部可观测结果那么就直接打死,不要废话.
    xss
        6
    xss  
       2017-06-28 09:25:36 +08:00
    @snnn 你行你上, 你解释. 连 libc 库是哪个调用约定都不知道, 我还能说啥.
    gnaggnoyil
        7
    gnaggnoyil  
       2017-06-28 13:32:06 +08:00
    @xss 首先 libc 库多了去了谁一定要和你说的那样玩

    其次,你是面向 C 和 POSIX 标准编程还是面向 glibc/Linux 的 ad hoc 实现编程?熟读语言标准的人都开始写 C 编译成浏览器 JavaScript 的编译器了,谭浩强式出身的人还在那里把 C 代码当作一个自己使用的特定平台的另一种语言的 trivial 对应.
    xss
        8
    xss  
       2017-06-28 14:13:57 +08:00
    @gnaggnoyil 你要是说平台是 arm, mips 这种架构下的 libc. 好吧, 那我无话可说, 的确有可能并不遵守默认的函数调用标准. 但是就楼主这个情形来说, 明显是 x86 下的 glibc. 或者我这么说更确切一点(?): 目前所有 x86 架构下的 lts linux 发行版本, glibc 的调用标准都是 cdecl.
    哪位能指教一下不是上述情况的 glibc ?
    liuyao729
        9
    liuyao729  
       2017-08-10 11:46:58 +08:00
    5 6 8
    zmj1316
        10
    zmj1316  
       2017-09-03 08:01:19 +08:00 via Android
    printf 这种不定长参数一般应该从左向右入栈吧,所以我猜 5 6 8
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3497 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 04:43 · PVG 12:43 · LAX 20:43 · JFK 23:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.