【问题标题】:C Programming: difference between ++i and i=i+1 from an assembler point of view?C 编程:从汇编程序的角度来看 ++i 和 i=i+1 之间的区别?
【发布时间】:2010-10-26 10:40:37
【问题描述】:

这是一个面试问题。我说他们是一样的,但这被判定为错误的反应。从汇编程序的角度来看,有什么可以想象的区别吗?我用默认的 gcc 优化和 -S 编译了两个简短的 C 程序来查看汇编器输出,它们是相同的。

【问题讨论】:

  • 面试官说的正确答案是什么?
  • 也许他混淆了++i和i++?
  • 但是即使 ++i 和 i++ 使用没有赋值也应该(使用好的优化器)编译成相同的,不是吗?

标签: c compiler-construction assembly compilation compiler-optimization


【解决方案1】:

面试官可能想要这样的答案:

i=i+1 必须加载i 的值,将其加一,然后将结果存储回i。相比之下,++i 可以使用一条汇编指令简单地增加值,因此理论上它可能更有效。但是,大多数编译器会优化掉差异,生成的代码会完全一样。

FWIW,您知道如何看待汇编这一事实使您成为比我多年来采访过的 90% 的人更好的程序员。放心吧,您不必与面试您的无知失败者一起工作。

【讨论】:

  • 从汇编的角度来看确实如此,但所有 x86 处理器都会对两个指令序列执行相同的操作 - inc [memadr] 无论如何都需要将值加载到隐藏寄存器。但是会发出不同数量的代码。
  • 我希望一个体面的编译器能够看到它在 LHS 和 RHS 中是相同的 i 并生成相同的代码。
  • 现代 SSA 编译器不会重写整个语句吗?第一条语句变为 i_2=i_1+1,第二条语句也变为 i_2=i_1+1。 i_1 和 i_2 变量可能没有分配到相同的寄存器。
  • 对于int i,如果您的编译器为这些语句中的任何一个生成次优的asm(当然启用了优化),这是一个错误,应该修复。我们关心的主流 ISA(gcc、clang、MSVC、ICC)的编译器都很好。没有理由期望这个 C 语句编译为任何特定的 asm:取决于周围的代码循环可以展开,或者增量可以折叠到其他操作中。
  • _Atomic int i 不一样,但这基本上就像 C++ 的重载运算符。
【解决方案2】:

看起来你是对的,他们错了。我在一次求职面试中遇到了类似的问题,我给出了被认为不正确的正确答案。

我自信地与我的面试官争论了这一点,他显然对我的无礼感到生气。我没有得到这份工作,但话又说回来,在“无所不知”的人手下工作也不是那么理想。

【讨论】:

  • 值得争论——我有同样的经历,指出面试官错在哪里以及为什么错了,然后得到了这份工作。
  • 同意。给出正确的答案总是比你认为面试官想要的要好。优秀的面试官会希望雇佣比他们更聪明的人。
【解决方案3】:

你可能是对的。一个天真的编译器可能会这样做:

++i to inc [ax]

i = i + 1 to add [ax], 1

但任何半明智的编译器只会优化在第一个版本中添加 1。

这一切都假设相关架构具有 inc 和 add 指令(就像 x86 一样)。

【讨论】:

  • 我会在采访中发表这样的评论。如果可用, ++i 肯定会使用增量指令,而 i = i + 1 在幼稚的编译器中可能不会这样做,但应该由体面的编译器进行优化以执行相同的操作。
  • 两个汇编器操作都无效,方括号表示通过 AX 访问内存插槽。也没有 inc ax 指令 - 必须使用 add 1 to AX。
  • 使用 ++i 表明您知道其中的区别。尝试说出你的真实意思总是一个好习惯。
  • @mP。两者都是正确的。 inc [ax] 表示递增 ax 寻址的内存,而 inc ax 表示递增 ax 本身。
  • 值得注意的是 ++i(或 i++,或 i=i+1)并不总是映射到 inc 指令。如果 i 是指向 int 的指针,则 ++i 将与 add i, 4 相同,因为 i 需要指向下一个 int,即 4 字节宽。如果 i 指向 long,则 ++i 将与 add i,8 相同,原因相同。
【解决方案4】:

为了保护面试官,上下文就是一切。 i的类型是什么?我们是在谈论 C 还是 C++(或其他类似 C 的语言)?你有没有得到:

++i;
i = i + 1;

还是有更多的上下文?

如果有人问我这个问题,我的第一反应会是“我易变吗?”如果答案是肯定的,那么差异是巨大的。如果不是,则差异很小且语义上的差异,但实际上没有差异。就是解析树的区别,以及生成的子树的最终意义。

所以听起来你在务实方面是正确的,但语义/批判性思维方面是错误的。

为了攻击面试官(没有上下文),我不得不想知道这个问题的目的是什么。如果我问这个问题,我想用它来了解候选人是否知道细微的语义差异、如何生成解析树、如何批判性地思考等等。我通常会问我的面试者一个 C 问题,几乎每个候选人都会出错 - 这是设计使然。我实际上并不关心问题的答案,I care about the journey that I will be taking with the candidate 以达成理解,它告诉我的不仅仅是一个琐事问题的正确/错误。

【讨论】:

  • 那是知识产权。
  • 您认为volatile int i 的区别到底是什么?它们都与大多数编译器编译相同。 C标准/as-if规则没有指定任何关于使用单个指令(原子wrt。中断但不是其他内核)进行内存目标增量的任何内容。 GCC 确实 错过了使用 volatile 的 x86 的单个 memory-dst 指令执行 ++ii=i+1 的优化,但 clang 对易失性和非易失性都进行了优化:godbolt.org/z/j46qGF .因此,对于这两种编译器,++ii=i+1 之间仍然没有区别,仅适用于 volatile 与 non
  • 是否有一个嵌入式编译器让volatile 使++i 有很大不同?
【解决方案5】:

在 C++ 中,这取决于 i 是 int 还是 object。如果它是一个对象,它可能会生成一个临时实例。

【讨论】:

  • true,但问题指定问题在 C 中
  • 并假设对象的类重载了++操作符
  • AFAIK 如果 ++ 没有重载,这是真的。
【解决方案6】:

上下文是这里的主要内容,因为在优化的版本构建中,如果 i++ 可用于简单的 [inc eax],编译器将优化它。而像 int some_int = i++ 这样的东西需要将 i 值存储在 some_int FIRST 中,然后才增加 i。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    • 2013-08-27
    • 2017-05-17
    • 1970-01-01
    • 2020-02-26
    • 2016-06-29
    • 2019-06-25
    相关资源
    最近更新 更多