为什么不是更频繁地使用Assembly编写的程序?
似乎是一个主stream的观点,程序集编程需要更长的时间,比C这样的更高级的语言更难以编程。因此,似乎推荐或假定,由于这些原因,编写更高级的语言更好并且为了更好的便携性。
最近我一直在用x86汇编编写代码,而且我发现可能这些原因不是真的,除了可移植性。 也许这是一个熟悉和知道如何写好汇编的问题。 我还注意到,在汇编中的编程与在HLL中编程完全不同。 也许一个好的和经验丰富的汇编程序员可以像编写C语言的经验丰富的C程序员一样方便快捷地编写程序。
也许是因为程序集编程与HLL完全不同,所以需要不同的思路,方法和方法,这使得编程对于不熟悉的程序来说显得非常尴尬,所以给程序编写不好的名字。
如果可移植性不是问题,那么C对于像NASM这样的好的汇编器会有什么样的影响呢?
编辑:只是要指出。 当你在汇编写作时,你不必写在指令代码中。 您可以使用macros和过程以及您自己的约定来进行各种抽象,以使程序更模块化,更易于维护,更易于阅读。 这是熟悉如何编写好的汇编进来的地方。
与较高级别的语言相比,ASM的可读性较差 , 不能真正维护 。
另外, ASM开发人员比其他更stream行的语言less得多,例如C.
此外,如果您使用更高级的语言,并且新的ASM指令可用 (例如SSE),则只需更新编译器,旧代码就可以轻松使用新的指令。
如果下一个CPU有两倍的寄存器呢?
这个问题的反面是: 编译器提供了什么function?
我怀疑你可以/想要/应该优化你的ASM比gcc -O3
更好。
地狱,我是一个编译器。
在阅读本文时,我只是扫描了数千行代码。 我浏览了数百万种基于大量学术研究的数百种不同的优化技术来优化您的单一行的数百万种可能性。 当我将一个三线环路转换成数千条指令以加快速度时,我不会感到任何尴尬,甚至不是轻微的尴尬。 我毫不惭愧地去做大量的优化工作,或做最肮脏的伎俩。 如果你不想要我,也许一两天,我会按你喜欢的方式行事。 我可以随时转换我正在使用的方法,甚至不需要更改代码的一行。 我甚至可以向你展示你的代码在汇编,不同的处理器体系结构和不同的操作系统以及不同的汇编约定中的外观。 是的,都在几秒钟内。 因为,你知道,我可以; 你知道,你不能。
PS哦,顺便说一下,你没有使用你写的一半的代码。 我帮了你一个忙,把它扔掉了。
我已经写了6502,Z80,6809和8086芯片的汇编程序。 一旦C编译器可用于我正在处理的平台,我就停止这样做了,立即变得至less提高了10倍。 大多数优秀的程序员使用他们使用的工具是合理的。
我喜欢使用汇编语言进行编程,但是需要更多的代码才能完成与高级语言相同的function,并且在代码行和错误之间存在着直接的关联。 (这是几十年前在“神话人月”中解释的 。)
把C想象成“高级程序集”是有可能的,但是要比上面的步骤要高一些,而且你处于一个不同的世界。 在C#中,你不必三思而后行:
foreach (string s in listOfStrings) { /* do stuff */ }
这可能是数十行,也可能是上百行代码,每个实现它的程序员都会采取不同的方法,下一个出现的人将不得不弄清楚。 所以如果你相信(尽可能多的)程序主要是为了让别人阅读,程序集的可读性比典型的HLL低。
编辑:我积累了用于常见任务的个人代码库,以及用于实现C类控制结构的macros。 但是在九十年代,当GUI成为常态的时候,我碰壁了。 在常规的事情上花费了太多的时间。
几年前,ASM最重要的任务是编写代码来对付恶意软件。 没有用户界面,所以这是所有有趣的部分没有膨胀。
除了其他人的可读性,可维护性,更短的代码,因此更less的错误,更容易的答案,我会添加一个额外的原因:
程序速度。
是的,在汇编中,您可以手动调整代码,以利用每一个循环,并尽可能快地完成。 但谁有时间? 如果你写一个不是完全愚蠢的C程序,编译器会为你做一个非常好的优化工作。 大概至less95%的优化你手工完成,而不必担心跟踪它的任何。 这里肯定有90/10的规则,最后5%的优化最终将占用你95%的时间。 那为什么要麻烦?
如果一个平均的生产程序有10万行代码,每行大约有8-12个汇编指令,那就是100万条汇编指令。
即使你可以用体面的速度手写所有这些(记住,它是你必须写的8倍的代码),如果你想改变一些function,会发生什么? 了解你几百万周前从这一百万条指令中所写的内容是一场噩梦! 没有模块,没有类,没有面向对象的devise,没有框架,没有任何东西。 而且,即使是最简单的事情,你写的类似代码的数量也是令人望而生畏的。
另外,你不能像高级语言那样优化你的代码。 例如C语言,因为你描述你的意图,不仅是你的代码,在汇编中你只写代码,而是执行一个疯狂的优化次数,所以汇编器不能真正对你的代码进行任何有价值的优化。 你所写的是你所得到的,相信我,你无法可靠地优化你在写入时修补和修补的一百万条指令。
那么我在过去一直在写大量的程序集,而且我可以向你们保证,当我用高级语言编写程序时,我的工作效率会更高。
合理的汇编程序能力是一项有用的技能,特别是在任何系统级别或embedded式编程的情况下工作,并不是因为必须编写那么多的汇编程序,而是因为有时了解该程序箱的function非常重要。 如果您对汇编程序的概念和问题没有深入的了解,这可能会非常困难。
但是,对于在汇编程序中实际编写大量代码,有几个原因没有完成。
-
根本没有(几乎)需要。 除了像早期的系统初始化和隐藏在C函数或macros中的一些汇编代码片断之外,所有可能曾经用汇编语言编写的低级代码都可以用C或C ++编写。
-
高级语言(甚至C和C ++)中的代码将function压缩成更less的行,并且有相当多的研究表明,错误的数量与源代码的行数相关。 也就是说,在汇编语言和C语言中解决的同样的问题,由于其更长的时间,在汇编语言中会有更多的错误。 同样的观点也促使人们转向Perl,Python等更高层次的语言。
-
在汇编程序中编写程序时,必须处理问题的每一个方面,从详细的内存布局,指令select,algorithmselect,堆栈pipe理等等。高级语言将所有这一切都从你手中带走,这就是为什么这么紧密LOC的条款。
从本质上讲,以上所有内容都与汇编程序与C语言或其他语言的抽象级别有关。 汇编程序迫使你做出自己的抽象,并通过自律来维护它们,任何像C这样的中级语言,尤其是更高级的语言,都能为你提供开箱即用的抽象,以及相对容易地创造新的能力。
作为一个在embedded式编程领域花费大量时间的开发人员,我认为汇编远非死亡/过时的语言。 编码(例如,在驱动程序中)有一定的接近金属级别,有时不能用高级语言准确或有效地expression。 我们用汇编写几乎所有的硬件接口例程。
这就是说,这个汇编代码被包装,它可以从C代码调用,并被视为一个库。 由于许多原因,我们不会在汇编中编写整个程序。 首先是便携性; 我们的代码库用于多种使用不同架构的产品,我们希望最大限度地提高可共享的代码量。 其次是开发者熟悉。 简而言之,学校不像以前那样教授集会,而且我们的开发人员在C方面比在集会方面的生产力要高得多。 另外,我们有许多可用于我们C代码的“额外”(像库,debugging器,静态分析工具等),这些代码不能用于汇编语言代码。 即使我们想编写一个纯assembly程序,我们也不能这样做,因为几个关键的硬件库只能作为C库使用。 从某种意义上说,这是一个鸡/鸡蛋的问题。 由于没有足够的库和开发/debugging工具,人们被驱逐出集合,但是库/工具不存在,因为没有足够的人使用集合来保证创build它们。
最后,任何语言都有一个时间和地点。 人们使用他们最熟悉和生产的东西。 在程序员汇编中可能总会有一个地方,但是大多数程序员会发现他们可以用更高级的语言编写代码,而这种代码的执行时间要less得多。
当你在汇编写作时,你不必写在指令代码中。 您可以使用macros和过程以及您自己的约定来进行各种抽象,以使程序更模块化,更易于维护,更易于阅读。
所以你基本上说的是,通过熟练使用一个复杂的汇编程序,你可以使你的ASM代码更接近C(或者是你自己发明的另一个低级语言),直到最终你只是和C程序员一样高效。
这是否回答你的问题? 😉
我不这么说,我已经用这个汇编程序和系统编写了程序。 更好的是,汇编器可以针对一个虚拟处理器,而一个单独的翻译器编译目标平台的汇编器的输出。 就像LLVM的IF一样,但是在早期的约会时间约为10年。 所以它具有可移植性,加上为效率要求编写特定目标asssembler的例程。
使用该汇编程序编写的代码大约与C相当,并且与GCC-3(当时我参与其中)相比,汇编程序/译码器产生的代码大致上一样快,通常较小。 规模是非常重要的,公司有很less的程序员,并愿意教新雇用一种新的语言,才可以做任何有用的事情。 而且我们还有备份,那些不了解汇编程序的人(例如客户)就可以使用相同的调用约定来编写C语言并编译为同一个虚拟处理器,从而使其接口整齐。 所以这感觉像是一个边缘的胜利。
那就是在开发汇编技术,图书馆等方面有多年的工作。 不可否认的是,它们中的大部分都是为了便于携带而devise的,如果它只是针对一种build筑而言,那么全唱的全舞蹈汇编程序就会容易得多。
总之:你可能不喜欢C,但这并不意味着使用C的努力比想出更好的东西更努力。
assembly不能在不同的微处理器之间移植。
我们不再去外面的卫生间,或者为什么我们不讲拉丁语或亚拉姆语。
技术出现,使事情变得更容易和更容易获得。
编辑 – 停止冒犯人们,我删除了某些词语。
为什么? 简单。
比较一下:
for (var i = 1; i <= 100; i++) { if (i % 3 == 0) Console.Write("Fizz"); if (i % 5 == 0) Console.Write("Buzz"); if (i % 3 != 0 && i % 5 != 0) Console.Write(i); Console.WriteLine(); }
同
.locals init ( [0] int32 i) L_0000: ldc.i4.1 L_0001: stloc.0 L_0002: br.s L_003b L_0004: ldloc.0 L_0005: ldc.i4.3 L_0006: rem L_0007: brtrue.s L_0013 L_0009: ldstr "Fizz" L_000e: call void [mscorlib]System.Console::Write(string) L_0013: ldloc.0 L_0014: ldc.i4.5 L_0015: rem L_0016: brtrue.s L_0022 L_0018: ldstr "Buzz" L_001d: call void [mscorlib]System.Console::Write(string) L_0022: ldloc.0 L_0023: ldc.i4.3 L_0024: rem L_0025: brfalse.s L_0032 L_0027: ldloc.0 L_0028: ldc.i4.5 L_0029: rem L_002a: brfalse.s L_0032 L_002c: ldloc.0 L_002d: call void [mscorlib]System.Console::Write(int32) L_0032: call void [mscorlib]System.Console::WriteLine() L_0037: ldloc.0 L_0038: ldc.i4.1 L_0039: add L_003a: stloc.0 L_003b: ldloc.0 L_003c: ldc.i4.s 100 L_003e: ble.s L_0004 L_0040: ret
它们在function上是相同的。 第二个不是汇编,而是.NET IL(中间语言,类似于Java的字节码)。 第二编译将IL转换为本地代码(即几乎汇编),使其更加隐秘。
即使在x86(_64)上,我也猜测ASM在通过使用编译器难以优化的指令获得大量收益的情况下是有意义的。 例如x264使用了很多asm编码,速度的提升是巨大的。
我相信有很多原因,但我能想到的两个很快的原因是
- 汇编代码肯定比较难阅读(我认为编写代码更费时间)
- 当你有一个庞大的产品开发团队时,把代码分成逻辑块和接口保护是很有帮助的。
早期的发现之一(你会发现它来自Brooks的“ 神话人月” ,这是从二十世纪六十年代的经验中得来的),人们在一种语言中或多或less地在一种语言中是有效的。 这显然不是普遍真实的,当被推得太远的时候可以被打破,但是布鲁克斯时代的高级语言是普遍的。
因此,获得生产力的最快方法是使用语言,其中一行代码做得更多,而且确实起作用,至less对于像FORTRAN和COBOL这样复杂的语言,或者给出更现代的例子C.
可移植性一直是一个问题,至less在最终的时候是如此。 编程行业每年花费数十亿美元来移植旧的软件,在写它的时候,“显然”没有任何可移植性的问题。
由于程序集变得不那么普遍:随着高级语言的成熟,汇编语言指令集为编程人员提供了更less的便利,而编译程序的便利程度更高。
所以,现实地说,要做出正确的决定,比如说应该使用哪个寄存器,哪个指令的效率稍微高一些,可能是非常困难的。 编译器可以使用启发式algorithm来找出哪些折衷可能有最好的回报。 我们也许可以考虑通过较小的问题,并find本地优化,可能会打败我们现在非常复杂的编译器,但是平均情况下,一个好的编译器会比一个好的程序员可能会做的更好。 最终,像约翰·亨利那样,我们可能会击败机器,但是我们可能会认真地把自己烧到那里去。
我们的问题现在也大不相同。 在1986年,我试图弄清楚如何在小型程序中获得更多的速度,包括在屏幕上放置几百个像素; 我希望animation不那么生涩。 汇编语言的一个公平的例子。 现在我想弄清楚如何用契约语言和服务商的抵押贷款政策来代表抽象概念,而且我宁愿读一些与商界人士所说的语言相近的东西。 与LISPmacros不同的是,汇编macros在规则方面并没有太多的实现,所以即使你能够在一个合适的汇编程序中获得与DSL相当接近的东西,也会容易出现各种各样的怪癖,如果我在Ruby,Boo,Lisp,C#甚至F#中编写相同的代码,那么会导致我的问题。
如果你的问题很容易用高效的汇编语言来expression,那么给你更多的权力。
同样大部分人都说了。
在C发明之前的好日子里,当只有高级语言是COBOL和FORTRAN这样的东西的时候,有很多东西在不借助汇编程序的情况下是不可能做到的。 这是获得全部灵活性的唯一途径,能够访问所有的设备等等。但是然后C被发明了,几乎任何可能的组装都可能在C中。我写了很less的程序集然后。
也就是说,我认为这对于新程序员学习编写汇编程序是非常有用的练习。 不是因为他们真的会使用它,而是因为那么你就明白计算机内真正发生了什么。 我看到很多编程错误和程序员的代码效率低下,他们完全不知道比特,字节和寄存器真正发生了什么。
我已经编程了大约一个月。 我经常用C语言编写一段代码,然后编译成程序集来帮助我。 也许我没有利用C编译器的全部优化function,但似乎我的C asm源代码包含了不必要的操作。 所以我开始看到,一个优秀的C编译器优于一个好的汇编编码器的说法并不总是正确的。
无论如何,我的汇编程序是如此之快。 而且我使用汇编的时间越短,写出我的代码的时间就越less,因为这实际上并不难。 另外关于assembly可读性差的评论是不正确的。 如果您正确地标记程序并在需要进一步阐述时发表意见,则应该全部设置。 事实上,对于程序员来说,汇编更清楚,因为他们看到了处理器层面正在发生的事情。 我不知道其他程序员,但对我来说,我喜欢知道发生了什么事情,而不是处于某种黑盒子里。
因此,编译器的真正优势在于编译器可以理解模式和关系,然后自动将它们编码到源代码中的适当位置。 一个stream行的例子是C ++中的虚函数,它要求编译器最佳地映射函数指针。 然而,编译器仅限于编译器制造商允许编译器执行的操作。 这导致程序员有时不得不借助他们的代码求助于奇怪的事情,增加了编码时间,而这些时间可以通过汇编来完成。
我个人认为市场大力支持高级语言。 如果汇编语言是当今唯一的语言,那么他们的编程人数就会减less大约70%,谁知道我们的世界将会在哪里,可能早在90年代。 更高层次的语言吸引更广泛的人群。 这使得更多的程序员能够build立我们世界所需的基础设施。 像中国和印度这样的发展中国家从Java这样的语言中受益颇多 这些国家将迅速发展自己的IT基础设施,人们将变得更加互联。 所以我的观点是高级语言的stream行并不是因为它们产生了高级代码,而是因为它们有助于满足全球市场的需求。
我现在正在学习comp的组件,虽然这很有趣,但写入也是非常低效的。你必须在头脑中保留更多的细节才能使事情顺利进行,而且写同样的东西也慢。 例如,C ++中一个简单的6行循环可以等于18行或更多的程序集。
就个人而言,学习如何在硬件层面减less工作的乐趣非常有趣,它让我更好地理解计算如何工作。
C语言对于一个好的汇编语言来说就是语言C.types检查。 循环结构。 自动堆栈pipe理 (几乎)自动variablespipe理。 汇编器中的dynamic内存技术是一个巨大的麻烦。 做一个正确的链表是正确的比较C或更好的名单foo.insert()。 而debugging – 呃,没有比较容易debugging的比赛。 高岭土在那里赢得了胜利。
我编写了近一半的汇编程序,这让我很容易在assmebler中进行思考。 它帮助我了解C编译器正在做什么,这又可以帮助我编写C编译器可以有效处理的代码。 用C语言编写的一个经过深思熟虑的例程可以被编写成只需要一点点工作就能完成你想要的汇编程序输出 – 而且是可移植的! 因为跨平台的原因,我已经不得不重写了一些较老的asm例程,并且没有什么乐趣。
No, I'll stick with C and deal with the occasional slight slowdown in performance against the productivity time I gain with HLL.
I can only answer why I personally don't write programs in assembly more often, and the main reason is that it's more tedious to do. Also, I think that it is easier to get things subtly wrong without noticing immediately. Eg, you might change the way you use a register in one routine but forget to change this in one place. It'll assemble fine and you may not notice until much later.
That said, I do think there are still valid uses for assembly. For instance, I have a number of pretty optimised assembly routines for processing large amounts of data, using SIMD and following the paranoid "every bit is sacred"[quote V.Stob] approach. (But note that naive assembly implementations are often a lot worse than what a compiler would generate for you.)
C is a macro assembler! And it's the best one!
It can do nearly everything assembly can, it can be portable and in most of the rare cases where it can't do something you can still use embedded assembly code. This leaves only a small fraction of programs that you absolutely need to write in assembly and nothing but assembly.
And the higher level abstractions and the portability make it more worthwhile for most people to write system software in C. And although you might not need portability now if you invest a lot of time and money in writing some program you might not want to limit yourself in what you'll be able to use it for in the future.
People seem to forget that there is also the other direction.
Why are you writing in Assembler in the first place? Why not write the program in a truly low level language?
代替
mov eax, 0x123 add eax, 0x456 push eax call printInt
you could just as well write
B823010000 0556040000 50 FF15.....
That has so many advantages, you know the exact size of your program, you can reuse the value of instructions as input for other instructions and you do not even need an assembler to write it, you can use any text editor…
And the reason you still prefer Assembler about this, is the reason other people prefer C…
Because it's always that way: time pass and good things pass away too 🙁
But when you write asm code it's totally different feeling than when you code high-level langs, though you know it's much less productive. It's like you're a painter: you are free to draw anything you like the way you like with absolutely no restrictions(well, only by CPU features)… That is why I love it. It's a pity this language goes away. But while somebody still remembers it and codes it, it will never die!
$$$
A company hires a developer to help turn code into $$$. The faster that useful code can be produced, the faster the company can turn that code into $$$.
Higher level languages are generally better at churning out larger volumes of useful code. This is not to say that assembly does not have its place, for there are times and places where nothing else will do.
The advantage of HLL's is even greater when you compare assembly to a higher level language than C, eg Java or Python or Ruby. For instance, these languages have garbage collection: no need to worry about when to free a chunk of memory, and no memory leaks or bugs due to freeing too early.
As others mentioned before, the reason for any tool to exist is how efficiently it can work. As HLLs can accomplish the same jobs as many lines of asm code I guess it's natural for assembly to be superseded by other languages. And for the close-to-hardware fiddling – there's inline assembly in C and other variants as per language. Dr. Paul Carter in says in the PC Assembly Language
"…a better understanding of how computers really work at a lower level than in programming languages like Pascal. By gaining a deeper understanding of how computers work, the reader can often be much more productive developing software in higher level languages such as C and C++. Learning to program in assembly language is an excellent way to achieve this goal."
We've got introduction to assembly in my college courses. It'll help to clear concepts. However I doubt any of us would write 90% of code in assembly. How relevant is in-depth assembly knowledge today?
Flipping through these answers, I'd bet 9/10 of the responders have never worked with assembly.
This is an ages old question that comes up every so often and you get the same, mostly misinformed answers. If it weren't for portability, I'd still do everything in assembly myself. Even then, I code in C almost like I did in assembly.