我使用高级语言(Python,C#,VBA,VB.NET)编程已有大约10年的时间,而对于“幕后”,我完全不了解。

我想知道学习汇编的好处是什么,对作为程序员的我有什么帮助?您能否提供给我一个资源,向我展示我在高级代码中编写的代码与汇编中发生的代码之间的确切联系?

评论

如果您真的想了解代码的深层内容,则可以参阅英特尔处理器手册(仅介绍部分):download.intel.com/products/processor/manual/325462.pdf。也许这比您想要的要深一些,但是我发现它很有用。

如果您想了解在.Net中专门发生的情况,您可能想了解有关CIL的更多信息。它在某些方面类似于组装,但是更高层次。因此,比实际组装更容易理解。

如果您学习汇编语言,则可以通过在其外部声明变量来避免想到正在优化for循环。例子

哦,我的上帝。您刚刚使我想起了大约一年前我在大学上的汇编语言课。看到我们理所当然地将极其简单的内容翻译成成百上千个甚至更小,更底层的操作,真是令人惊讶。电脑是非凡的机器。

学习汇编将使您对编程语言的概念产生深切而持久的热爱,从而使您不必再编写汇编中的复杂代码。

#1 楼

因为您将了解它是如何工作的。


您将了解函数调用不是免费的,以及调用栈为何会溢出(例如,在递归函数中)。您将了解如何将参数传递给函数参数,以及如何将参数传递给函数参数(复制内存,指向内存)。
您将了解内存不是免费的,自动内存管理具有多么重要的意义。内存不是您“仅拥有”的东西,实际上它需要管理,照顾和最重要的是,不要忘记(因为您需要自己释放它)。
您将了解控制流的工作原理从根本上讲。
您将更欣赏高级编程语言中的构造。

归结为,我们用C#或Python编写的所有内容都需要转换为计算机可执行的一系列基本操作。很容易从类,泛型和列表理解的角度来考虑计算机,但是这些仅存在于我们的高级编程语言中。

我们可以想到看起来真的不错但没有的语言构造。不能很好地转换为低级的处理方式。通过了解它的真正工作原理,您将更好地理解事情为什么以它们的方式工作。

评论


+1表示“您将更欣赏高级编程语言中的结构”。好答案。

–DevSolo
2012年7月13日在19:44

除了经过几周的asm训练之外,您将开始将C视为高级编程语言。除非您要与低级别的嵌入式设备开发人员交谈,否则大声说出来会使大多数人认为您有点疯狂。

–丹在火光中摆弄
2012年7月13日在19:53

@Dan:这些术语如何随时间变化真是有趣。 20年前,当我刚开始编程时,如果您问过一个人,他们会说“当然C是一种高级语言!”那应该很明显;它提供了标准化的堆和内存访问模型。这是对硬件的严重抽象。在低级语言中,您必须自己跟踪所有内存地址,或者如果您正在做一些真正想做的事情,则可以编写自己的堆分配器!所以我想知道,今天使事物高层次或低层次的标准是什么?

–梅森·惠勒
2012年7月13日在22:14



高级/低级不是二进制文件。一个全面的程序员在其职业生涯中既编写了汇编语言又编写了Python,则可能会将C或C ++视为中级语言。

–拉塞尔·博罗戈夫(Russell Borogove)
2012年7月14日在1:31

这些是需要理解的重要事项,但是很容易从抽象的层次上加以介绍:例如,在机器指令级别的计算机入门课程中。我不是汇编程序员,但如果我自己这么说的话,我会很好地理解它们。在一些SO答案中,我看到了有关指令缓存和流水线的讨论,而这些确实使我头疼。但是(到目前为止)答案中缺少该子指令级别。那么,与学习基础知识课程相比,实际学习汇编程序编程有什么好处?

–alexis
2012年7月14日下午13:10

#2 楼

通常,它将使您更好地理解什么是“内幕”,以及指针如何工作以及寄存器变量和体系结构的含义(内存分配和管理,参数传递(按值/按引用)等)。 br />
要快速浏览C,这是怎么回事? >
#include <stdio.h>

main()
{
  puts("Hello World.");
  return(0);
}


评论


+1:提示!通过查看C编译器的功能,您可以学到很多东西。

–乔治
2012年7月13日在18:43



... SOS是故意的吗? (致电寻求帮助,等等)

–伊兹卡塔
2012年7月13日在19:53

@Izkata哈哈..好一个,我什至没有注意到。我有一个标准的so.c文件来解决stackoverflow问题(例如我有so.py,so.awk等),以便快速测试内容。所以... :)

–莱文
2012年7月13日19:55



如果使用gcc -O -c -g -Wa,-ahl = so.s so.c进行编译,则可以看到每行C代码的汇编输出。这使得了解正在发生的事情变得容易一些。

–麦基·梅塞尔(Mackie Messer)
2012年7月13日在22:28

是的,输出很长。您可以搜索5:so.c来找到so.c的第5行的代码。

–麦基·梅塞尔(Mackie Messer)
2012年7月13日在22:53

#3 楼

我认为您在这里找到的答案是:http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language
文章引文:

没错,您可能不会发现自己正在汇编中编写下一个客户的应用程序,学习汇编仍然有很多好处。如今,汇编语言主要用于直接硬件操纵,访问专用处理器指令或解决关键性能问题。典型的用途是设备驱动程序,低级嵌入式系统和实时系统。
事实是,高级语言变得越来越复杂,并且写入的ADT(抽象数据类型)越多,支持这些选项会产生更多开销。在.NET实例中,可能是膨胀的MSIL。想象一下,如果您知道MSIL。这就是汇编语言的亮点。
汇编语言与程序员一样接近处理器,因此精心设计的算法非常出色-汇编对于速度优化非常有用。一切都与性能和效率有关。汇编语言使您可以完全控制系统资源。就像组装流水线一样,您编写代码将单个值压入寄存器,直接处理内存地址以检索值或指针。发生”。请注意,汇编语言是神秘的,应用程序源代码的大小比高级语言大得多。但是请不要误会,如果您愿意花费时间和精力进行装配,您会变得更好,并且会在该领域脱颖而出。

此外,我推荐这本书是因为它具有简化的计算机体系结构版本:
计算系统概论:从位与门到C及其他,2 / e
Yale N. Patt,德克萨斯大学奥斯汀分校
伊利诺伊大学厄巴纳/香槟分校的Sanjay J.Patel

评论


这描述了ASM的用途,并提到了HLL膨胀,但是学习ASM的唯一特定好处是编写超快速代码。是的,但是即使您学习了ASM,您实际将其纳入应用程序的可能性有多大?假设您编写的是业务应用程序,而不是硬件控制器或设备驱动程序。

–user25946
2012年7月13日在21:48

+1 @notkilroy,感谢您的链接,尤其是推荐书

–安东尼
2012年7月13日23:56

@Jon,我真的不明白为什么要开发商务软件。如果您是DBA或正在编写编译器,或者内存空间有限,那是一回事,但是我认为没有多少人经常接触它。优化主要由编译器负责,这是在汇编中编写的最大原因。有时在跟踪内存泄漏时很有用。

–艾米莉
2012年7月14日在1:03



由于我专门研究业务应用程序,因此我主要依靠使用4GL的基于SQL的应用程序开发工具。它们使我能够快速创建应用程序原型并将其自定义到生产系统中。很少需要编写可调用的cfunc。交付时间和修改时间是我世界中的重要因素!

–弗兰克·R。
2012年7月14日在3:09



我完全不同意。自动化优化器通常可以击败人类程序员来创建快速的程序集。

– DeadMG
2012年7月15日在22:25

#4 楼

以我的拙见,它并没有太大帮助。

我以前非常了解x86汇编。当我的课程中出现汇编时,它会有所帮助,在面试中它会出现一次,并帮助我证明编译器(Metrowerks)正在生成不良代码。计算机的实际运行方式令人着迷,而学习它使我在智力上更加丰富。当时玩起来也很有趣。

但是,如今的编译器比几乎任何代码段上的任何人都更擅长生成汇编。除非您正在编写编译器或检查编译器是否在做正确的事情,否则您可能在通过学习来浪费时间。

我承认,C ++程序员仍然有用地提出的许多问题是通过知道组装。例如:我应该使用堆栈变量还是堆变量?我应该按值或const引用传递?但是,我认为在几乎所有情况下,这些选择都应基于代码的可读性而不是节省计算时间。 (例如,只要您想将变量限制在范围内,就使用堆栈变量。)

我的拙劣建议是专注于真正重要的技能:软件设计,算法分析和问题解决。凭借开发大型项目的经验,您的直觉将得到改善,这比知道组装具有更多的价值(在我看来)。

评论


我不同意如果您对某种算法有广泛的了解,并且对硬件有很好的了解,通常可以创建比编译器可以更好地优化的汇编代码,因为它必须安全运行。在进行优化时,大致了解代码如何转换为程序集也很有帮助。

–狮子座
2012年7月14日在17:24

优化不是学习它的原因。在这方面,我同意尼尔·G的观点。他低估了他对真实机器的基本了解如何告诉他如何使用高级语言。

– Warren P
2012年7月16日在1:23



以我的经验,通过实现,测量事物,寻找方法来优化它,实现更好的方法等,可以使算法快速实现。有机会反复细化。

– gnasher729
15年4月24日在18:51

如今,很少要用汇编进行编码的情况,但是了解其工作原理是非常宝贵的,对于那些想知道其全部工作原理的人来说将大有帮助。例如,当我不知道事情为什么会发生时,我发现很难跟随事情。

– Winger Sendon
16年8月19日在15:45

#5 楼

您应该熟悉所使用系统中的一个“更深层次”。一口气跳得太远并不是一件坏事,但可能没有人们期望的那样有用。

使用高级语言的程序员应该学习低级语言(C是一个很好的选择)。当您告诉计算机实例化一个对象,创建一个哈希表或一个集合时,无需一路进行汇编就可以了解幕后的情况,但是您应该能够编写代码

对于Java程序员来说,学习一些C语言可以帮助您进行内存管理,传递参数。用C编写一些扩展的Java库将有助于理解何时使用Set的实现(您要散列还是树?)。在线程环境中处理char *将有助于理解为什么String是不可变的。

进入下一个层次... AC程序员应该熟悉汇编和汇编类型(通常在嵌入式系统中找到)系统商店)可能很容易理解门级的事物。那些与盖茨合作的人应该了解一些量子物理学。而那些量子物理学家,他们仍然在努力弄清楚下一个抽象是什么。

评论


更深一层是关于正确的。我倾向于花一些时间,但是假设与为C#程序员学习MSIL相比,x86汇编知识值得投资。作为一个在大学学习组装和固态物理学的人,我不认为了解门设计的物理知识对我有帮助,除了毕业于电子学位。

–穆罕默德·阿尔卡鲁里(Muhammad Alkarouri)
2012年7月14日在20:13

@MuhammadAlkarouri我的思路是理解电流泄漏,运行时间,电阻以及热量对系统的影响。对基本“为什么”的理解比起最小迹线分隔和操作公差的规则,有助于做出更多决策。

–user40980
2012年7月16日15:38

#6 楼

由于您没有使用您所知道的语言来提及C或C ++。我强烈建议您甚至在考虑组装之前就对它们进行充分的学习。 C或C ++将提供在托管语言中完全透明的所有基本概念,并且您将了解本页面中提到的大多数概念,以及可以在现实世界项目中使用的最重要的语言之一。这是您编程技能的真正附加值。请注意,汇编程序在非常特定的领域中使用,它几乎不如C或C ++有用。

我什至更进一步地说,在了解如何不受管理的情况下,您不应该沉迷于汇编程序。语言工作。这几乎是一本必读的书。

如果想更进一步,请学习汇编。您想知道如何精确地创建该语言的每种构造。它提供了很多信息,但级别复杂性却大不相同。

#7 楼

如果您精通一门语言,那么您至少应该对技术的基础知识至少了解一个抽象级别。

为什么?当出现问题时,对底层机制的了解使调试奇怪的问题变得更加容易,并且自然而然地编写了更有效的代码

以Python(/ CPython)为例,如果您开始遇到奇怪的崩溃或性能差的情况下,有关如何调试C代码的知识可能非常有用,与其引用计数内存管理方法的知识相同。这也将帮助您知道何时/是否将某些内容编写为C扩展,依此类推...

在这种情况下要回答您的问题,汇编知识的确不能帮助有经验的Python开发人员(抽象化步骤太多了-用Python完成的任何操作都会导致许多汇编指令)。

..但是,如果您有C的经验,那么就会知道“下一个层次”同样,如果您使用的是CoffeScript,那么了解Javascript非常有用。如果您正在使用Clojure,则对Java / JVM的了解会很有用。

这个想法也可以在编程语言之外使用-如果您正在使用Assembly,那么熟悉底层硬件的功能是一个好主意。 。如果您是一名Web设计人员,那么最好了解如何实现Web应用程序。如果您是汽车修理工,那么最好掌握一些物理知识

#8 楼

编写一个小的c程序,然后反汇编输出。就这样。但是,为增加或减少操作系统使用的“内务处理”代码做好准备。

组装可以帮助您了解引擎盖下发生的事情,因为它直接处理内存,处理器寄存器等。复杂的操作系统使事情复杂化,请尝试使用汇编语言对Arduino进行编程。

#9 楼

没有确切的答案,因为程序员并非全部。您是否需要知道潜伏在下面的东西?如果是这样,然后学习它。您只是出于好奇而只想学习它吗?如果是这样,然后学习它。如果这对您没有实际的好处,那为什么要麻烦呢?仅仅为了开车就需要机械师的知识水平吗?机械师是否仅需要在汽车上工作就需要工程师的知识水平?这是一个严肃的类比。技工可以是一个非常好的生产性技工,而无需深入研究工程师所掌握的车辆。音乐也一样。您是否真的想把旋律,和声和节奏的复杂性变成一个好的歌手或演奏者?不会。一些非常有才华的音乐家无法读懂乐谱,更不用说告诉您Dorian和Lydian模式之间的区别了。如果您愿意,可以,但不需要,您不需要。如果您是一名Web开发人员,那么程序集没有我能想到的实际用途。如果您使用的是嵌入式系统或某些特别的东西,则可能有必要,但如果确实如此,您就会知道。 :
http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html

#10 楼

实际上,最适合您的可能是一个(据我所知)在任何地方都不存在的类:该类将机器/汇编语言和存储寻址概念的简要概述与编译器构造的导览结合在一起,代码生成和运行时环境。

问题在于,使用像C#或Python这样的高级,远离硬件的语言,您并不会真正意识到这样一来,您就会变成数百甚至数千条机器指令,而您往往不会理解高级语言的几行代码如何导致大量存储空间的访问和修改。您不需要确切地知道“幕后花絮”是怎么回事,但是您需要了解正在发生的事情的范围以及对所发生事情的类型的一般概念。

#11 楼

我对这个问题的回答相对较新。现有答案涵盖了我过去所说的内容。实际上,这仍然是最重要的答案-“了解高级编程中的结构”这一点,但是我认为这是一种特殊情况,值得一提...
杰夫·阿特伍德(Jeff Atwood)的博客文章引用了一项研究,理解作业是理解编程的关键问题。学习者程序员可能会理解该符号仅表示计算机遵循的步骤以及该步骤所导致的原因,或者会因误导数学方程式等而永久困惑。

如果您了解以下内容, 6502汇编程序...

LDA variable
CLC
ADC #1
STA variable


这实际上只是步骤。然后,当您学习将其转换为赋值语句时...

variable = variable + 1;


您不需要对数学方程式的误导类推-您已经有了正确的思维方式将其映射到模型。根本没有帮助。

我学习了6502汇编程序作为第二语言,第一种是Commodore Basic,当时我并没有真正学到太多-部分是因为学到的东西很少,还因为那时的汇编程序似乎更加有趣。部分是因为时间,部分是因为我是14岁的怪胎。

我不建议做我做的事情,但是我想知道是否可以用一种非常简单的汇编语言研究一些非常简单的示例一个学习高级语言的有价值的入门。

#12 楼

除非您是编译器作者,或者需要高度优化的知识(例如数据处理算法),否则学习汇编代码将不会给您带来任何好处。

编写和维护用汇编语言编写的代码非常困难,因此即使您非常了解汇编语言,除非没有其他方法,否则不应该使用它。

“针对SSE进行优化:案例研究”一文显示了如果您要学习汇编语言,该怎么办?部件。作者设法将算法从100个周期/向量优化到17个周期/向量。

评论


作者没有在C ++版本中使用任何矢量指令或内在函数。您不需要汇编程序即可编写SSE代码。

– gnasher729
15年4月24日在18:55

@ gnasher729是的,您不需要。但是使用汇编,程序可以运行得更快。毕竟,人类比编译器更聪明(在极少数情况下)。

–BЈовић
15年4月27日在7:18

#13 楼

由于细节(寄存器分配等)的数量,汇编语言的编写不会给您神奇的速度提高,您可能会编写有史以来最简单的算法。

另外,现代的(读取-在70-80年代后设计的)处理器组件无法为您提供足够多的详细信息以了解正在发生的事情(也就是说-在大多数处理器上)。就调度指令而言,现代的PU(CPU和GPU)非常复杂。了解汇编(或伪汇编)的基础知识将有助于理解计算机体系结构的书籍/课程,这些书籍/课程将提供进一步的知识(缓存,无序执行,MMU等)。通常,您不需要了解复杂的ISA就可以理解它们(MIPS 5是非常流行的IIRC)。

为什么要了解处理器?它可能使您更多地了解正在发生的事情。假设您以朴素的方式编写矩阵乘法:

for i from 0 to N
    for j from 0 to N
        for k from 0 to N
            A[i][j] += B[i][k] + C[k][j]


就您的目的而言可能“足够好”(如果它是4x4矩阵,则可能会编译为矢量指令无论如何)。但是,在编译大量数组时,会有一些非常重要的程序-如何优化它们?如果您使用汇编语言编写代码,则可能会有所改善(除非您像大多数人那样做-同样以幼稚的方式,未充分利用寄存器,不断地将数据加载/存储到内存中,实际上程序的速度比HL语言慢) 。

但是,您可以反转线并神奇地获得性能(为什么?我将其保留为“作业”)-IIRC取决于大型矩阵的各种因素,甚至可以达到10倍。

for i from 0 to N
    for k from 0 to N
        for j from 0 to N
            A[i][j] += B[i][k] + C[k][j]


话虽如此-编译器正在努力做到这一点(gcc为石墨,而使用LLVM则为Polly)。他们甚至能够将其转换为(抱歉-我正在写对内存的阻塞):

for i from 0 to N
    for K from 0 to N/n
        for J from 0 to N/n
            for kk from 0 to n
                for jj from 0 to n
                    k = K*n + kk
                    j = J*n + jj
                    A[i][j] += B[i][k] + C[k][j]


总而言之-了解程序集的基础知识可以使您从处理器设计中挖掘各种“细节”,从而可以编写更快的程序。了解RISC / CISC或VLIW /矢量处理器/ SIMD / ...体系结构之间的差异可能会很好。但是,我不会从x86开始,因为它们往往非常复杂(可能也是ARM)-知道什么是寄存器等,恕我直言足以启动。

评论


我发现您提供了几个代码示例很有趣,但是它们都不是汇编语言。

–罗伯特·哈维(Robert Harvey)
2013年1月4日,1:13

#14 楼

通常,对于调试而言,这非常重要。当系统在指令中间中断并且错误没有意义时,您该怎么办?只要您只使用安全的代码,.NET语言的问题就不那么多了-系统几乎总是会保护您免受幕后操作的影响。

#15 楼

简而言之,我认为答案是因为如果您学习汇编,可以做更多的事情。学习汇编可以访问嵌入式设备编程,安全性渗透和规避,逆向工程和系统编程等领域,如果您不了解汇编器,则很难进行这些工作。

关于学习它以提高程序性能,这在应用程序编程中值得怀疑。在大多数情况下,在达到此优化级别之前,有很多事情需要首先关注,例如优化磁盘和网络上的I / O访问,优化构建GUI的方式,选择正确的算法,最大化所有核心,以最好的硬件来运行可以购买并从解释语言转换为编译语言。除非您要为其他最终用户创建软件,否则与程序员的小时工资相比,硬件是便宜的,尤其是在云可用性方面。

此外,您还必须权衡提高程序执行速度和代码的可读性。您在写上一个版本一年后,就遇到公交车,退出或返回代码库进行更改。

#16 楼

我会建议学习算法:排序,链接列表,二叉树,哈希等。

还请学习Lisp,请参阅“计算机程序的结构和解释” groups.csail.mit.edu/mac/classes/6.001/ abelson-sussman讲座将在此视频课程中教您所有您需要知道的内容,包括算法(如何基于一些基本命令,一个Lisp基本语言和一些汇编程序挑衅性来完成所有操作)。

最后您必须学习汇编器才能学习像ARM这样的简单工具(它在x86上使用的设备大约是x86的4倍)。

#17 楼

好吧,答案是仅仅因为您使用的语言必须在最后解释或编译为汇编器。无论是语言还是机器。

语言的设计源自CPU的工作方式。

我最后要说的是,不仅需要了解很少的汇编语言,还需要了解CPU架构,这是通过学习汇编语言来学习的。 />
一些示例:有很多Java程序员不理解为什么它不起作用,甚至不知道运行它时会发生什么。

String a = "X";
String b = "X";
if(a==b)  
    return true;


如果您了解一些汇编程序,您总会知道内存位置的内容与“指向”该位置的指针变量中的数字是不同的。 ,即使在已出版的书中,您也会读到类似JAVA原语那样通过值传递和通过引用传递对象的情况,这是完全错误的。 Java中的所有参数都是按值传递的,而Java不能将对象传递给函数,只能将指针传递给值。

如果您现在汇编的是显而易见的情况,要不是很复杂就很难解释,大多数作者只是在撒谎。

当然,这些都很微妙,但以后可能会给您带来真正的麻烦。如果您知道汇编程序不是问题,那么如果不是,则表示您将进行漫长的调试工作。

评论


您的第一段是完全不正确的:语言没有被编译为ASM,而是被编译为机器代码。解释器也不会编译为ASM,它们会解释代码或字节代码,并在预编译的机器代码上调用函数或方法。

–user7519
2012年7月13日在18:27

您声称有关Java的任何事情都不正确。以String开头a =“ X”;字符串b =“ X”; if(a == b)返回true;实际上这是== true的,因为编译器会执行String Interning。所有其他Java语句也是错误的。 Java没有指针,它有不同的引用。而且,这些都不以任何方式与汇编程序有关。 Java按值传递基元,并按值传递引用。 Java没有指针,因此它不能通过任何指针传递它们。再次与了解ASM无关。

–user7519
2012年7月13日在18:33



我一直认为高级语言会编译为对象(机器代码)或伪代码,而不是ASM。

–弗兰克·R。
2012年7月14日在3:40

@FrankComputer正确,但是机器代码字节将1:1映射为汇编指令,因此您可以轻松地在代码对象和ASM之间进行转换(反编译或汇编)

– dbr
2012年7月14日在20:56

上次使用@FrankComputer时,我将gcc编译后的C / C ++ / fortran / java / ada / etc转换为内部字节码,并将内部字节码转换为汇编器。然后,它将此汇编程序代码分派给汇编程序,以将其转换为机器代码。

–ctrl-alt-delor
2012年7月14日在21:06