明显操作的复杂代码

时间:2010-10-03 15:33:10

标签: c++ optimization inline-assembly

有时候,主要是出于优化目的,非常简单的操作被实现为复杂而笨拙的代码。

一个例子是这个整数初始化函数:

void assign( int* arg )
{
    __asm__ __volatile__ ( "mov %%eax, %0" : "=m" (*arg));
}

然后:

int a;
assign ( &a );

但实际上我不明白为什么会这样写...

你有没有看到任何有真正理由的例子?

5 个答案:

答案 0 :(得分:21)

就你的例子而言,我认为这是因为错误的假设,即在汇编中编写代码会自动更快。

问题在于写这篇文章的人并不明白为什么汇编有时可以更快地运行。也就是说,你比编译器更了解你正在尝试做什么,并且有时可以使用这些知识在更低级别编写代码,而不必根据编译器的假设进行编码。

在简单变量赋值的情况下,我严重怀疑它是否成立并且代码可能执行得更慢,因为它具有管理堆栈上的assign函数的额外开销。请注意,它不会明显变慢,这里的主要成本是代码不易读取和维护。

这是一个教科书示例,说明为什么在不理解为何是优化的情况下不应实施优化。

答案 1 :(得分:8)

似乎汇编代码意图是确保每次都完成对*arg int位置的赋值 - 在这方面阻止(故意)编译器的任何优化。

通常在C ++(和C ...)中使用volatile关键字来告诉编译器该值不应保存在寄存器中(例如)并从该寄存器中重用(优化以便得到更快的价值),因为它可以异步(通过外部模块,汇编程序,中断等......)。

例如,在函数中

  int a = 36;
  g(a);
  a = 21;
  f(a);

在这种情况下,编译器知道变量a是函数的本地变量,并且未在函数外部修改(a上的指针未提供给任何函数呼吁例如)。它可以使用处理器寄存器来存储和使用a变量。

总之,ASM指令似乎被注入到C ++代码中,以便而不是对该变量执行一些优化。

答案 2 :(得分:3)

虽然在集会中写一些东西有几个合理的理由,但根据我的经验,这些是不寻常的实际原因。在我能够研究其基本原理的地方,它们归结为:

年龄:代码是在很久以前编写的,它是处理时代编译器的最合理选择。通常,在大约1990年之前可以证明是合理的,恕我直言。

控制怪胎:有些程序员有trust issues with the compiler,但不倾向于调查其实际行为。

误解:一个令人惊讶的广泛而持久的神话是,用汇编语言编写的任何东西本身都会产生比在“笨拙”编译器中编写更有效的代码 - 所有神秘的函数进入/退出代码等等。当然有一些编译器值得这个声誉

要“冷静”:当时间和金钱不是因素时,有什么更好的方法来支持程序员激素水平的显着提高,而不是一些男子气概,最好是难以理解的汇编语言?

答案 3 :(得分:1)

你给出的例子似乎有缺陷,因为assign()函数可能比直接赋值变量慢,原因是调用带参数的函数涉及堆栈使用,而只是说int a = x很容易无需堆栈即可编译为高效代码。

我从使用汇编程序中受益的唯一一次是手动优化编译器生成的汇编程序输出,这是处理器速度通常在单个兆赫范围内的日子。算法优化倾向于提供更好的投资回报,因为您可以获得改进的数量级而不是小的倍数。正如其他人已经说过的那样,你去汇编程序的唯一其他时间是编译器或语言不能做你需要做的事情。使用C和C ++,这种情况很少发生。

很可能有人炫耀他们知道如何编写一些简单的汇编程序代码,使下一个程序员的工作更加困难,并且可能作为保护自己工作的一半措施。对于给出的示例,代码令人困惑,可能比本机C慢,可移植性较差,应该可以删除。当然,如果我在任何现代C代码中看到任何内联assmebler,我会期待丰富的评论解释为什么它是绝对必要的。

答案 4 :(得分:0)

让编译器为您优化。这种“优化”不可能有任何帮助......永远!