11

在 C 程序中使用汇编语言的目的是什么?编译器已经能够生成汇编语言。在什么情况下写汇编比写 C 更好?性能是一个考虑因素吗?

4

6 回答 6

15

除了大家所说的:并非所有 CPU 功能都暴露给 C。有时,特别是在驱动程序和操作系统编程中,需要显式使用特殊寄存器和/或命令,否则这些是不可用的。

还有向量扩展。

在编译器内在函数出现之前尤其如此。这些在一定程度上减轻了对内联汇编的需求。


内联汇编的另一个用例与 C 与反射语言的接口有关。具体来说,如果您需要在编译时不知道其原型的情况下调用函数,则汇编几乎是必需的。换句话说,当该函数的参数的数量和数据类型只是运行时变量时。在这种情况下,C 可变参数函数和stdarg机器不会帮助您 - 它们会帮助您解析堆栈帧,但不会构建堆栈帧。另一方面,在组装中,这是非常可行的。

这不是操作系统/驱动程序方案。至少有两种技术——Java 的 JNI 和 COM 自动化——这是必须的。在自动化的情况下,我说的是 COM 运行时使用它们的类型库来编组双接口的方式。

可以为此想到一个非常粗糙的 C 替代程序集,但它会像罪恶一样丑陋。


另一个用例:崩溃/运行时错误报告。对于事后调试,您希望在崩溃点尽可能多地捕获程序状态(即所有 CPU 寄存器),而汇编是比 C 更好的工具。


我只介绍了需要组装的情况。其他答案中涵盖了手动优化性能。

于 2013-01-03T02:08:26.477 回答
6

在少数情况下,手动优化的汇编语言可以比 C 编译器从 C 源代码生成的汇编语言更有效地运行。此外,对于习惯于汇编语言的开发人员来说,有些东西似乎更容易用汇编语言编写。

对于这些情况,许多 C 编译器允许内联汇编。

然而,随着 C 编译器变得越来越好并产生高效的代码,这种情况变得越来越少,并且大多数平台对一些低级软件类型进行了限制,这些软件通常是从用汇编程序编写中受益最多的软件类型。

于 2013-01-03T02:03:55.160 回答
4

一般来说,它是性能,但性能非常特殊。例如,编译器可能不会生成处理器的 SIMD 并行指令。通过利用处理器特定的数据格式,然后发出处理器特定的并行指令(例如 ARM NEON 或 Intel SSE),可以在图形或信号处理问题上出现非常快的性能。即使这样,一些编译器也允许使用内部函数在 C 中表达这些。

虽然过去常常使用汇编语言插入来手动优化关键功能,但那些日子已经基本完成。现代编译器非常好,而现代处理器具有非常复杂的时序要求,因此手动优化的代码通常不如预期的那么优化。

于 2013-01-03T02:05:30.237 回答
3

用 C 编写内联程序集有多种原因。我们可以简单地将原因分为必要不必要

出于不必要的原因,可能是:

  • 平台兼容性
  • 表现有关
  • 代码优化
  • 等等

我认为上面是不必要的,因为有时它们可​​以被丢弃或通过纯 C 实现。例如平台兼容性,您可以完全为每个平台实现特定版本,但是,使用内联程序集可能会减少工作量。在这里我们不打算过多谈论不必要的原因。

出于必要的原因,它们可能是:

  • 标准库的一些事情是不够的
  • 编译器不支持某些指令集
  • 目标代码生成不正确
  • 编写堆栈敏感代码
  • 等等

这些原因被认为是必要的,因为它们几乎不可能用纯 C 语言完成。例如,在旧的DOSes 中,软件中断INT21不可重入的。如果要写一个Virtual Dirve完全使用INT21编译器支持,那是不可能的。在这种情况下,您需要挂钩原始INT21,并使其可重入。但是,编译后的代码会使用 prolog/epilog 包装您的每个调用。因此,您永远无法破坏受限制的东西,或者您只是破坏了代码。您可以通过使用带有库的纯 C 语言来尝试任何技巧;但即使你能成功找到一个技巧,那意味着你找到了一个特定的订单编译器生成机器代码;这意味着:您试图让编译器将您的代码编译为完全机器码。那么,为什么不直接编写内联程序集呢?

这个例子解释了上面所有必要的原因instruction set not supported,但我认为这很容易想到。事实上,编写内联程序集的理由更多,但现在你对它们有了一些想法,等等。

于 2013-01-03T03:04:15.840 回答
2

出于好奇,我在这里添加一个具体示例,说明您只能在汇编中执行的不那么低级别的操作。我在大学时代的一本汇编书中读到了这一点,它被用来展示 C/C++ 的固有局限性,以及如何用汇编克服它。

问题是当参数的确切数量仅在运行时已知时,我如何调用函数?事实上,在 C/C++ 中,您可以轻松定义一个接受可变数量参数的函数,例如printf. 但是在调用该函数时,编译器想确切地知道必须传递多少个参数。您可能会通过比要求更多的参数,这不会造成任何伤害。但是,如果数量意外增长到 100 或 1000 个参数,并且必须从数组中挑选出来怎么办?解决方案当然是使用汇编,您可以在其中动态创建适当大小的堆栈帧,复制堆栈上的参数,调用函数,最后重置堆栈。

在实践中,这几乎不会是一个限制(除非您使用的库设计得非常糟糕)。像其他人在回答中指出的那样,在 C 中使用汇编的人有更好的理由这样做。不过,我认为这可能是一个有趣的事实。

于 2013-01-05T00:33:37.287 回答
0

我宁愿将其视为为特定平台编写非常特定代码的一种方式,优化虽然仍然很常见,但现在使用较少。C 语言中汇编的知识和用法也被全色帽子练习。

于 2013-01-03T02:11:58.267 回答