汇编语言总结

汇编语言学习体会

大一大二期间学写了一些高级语言,如C语言和C++。在对一些实际问题的编程处理上使用这些高级语言显得很是方便。于是在刚接触这门课的时候就对其实用性产生了怀疑和一些的抵触情绪。再学习了一段时间后,虽然对一些繁杂的指令有些讨厌;但还是硬着头皮学着下来了;但后来再经过实验课的学习感觉汇编语言并不是那么的枯燥无味,是很有实际用途的。在很多问题的处理上,汇编语言编程很是节省系统的资源。通过这一学期的学习,对汇编有了初步的掌握,可以说是汇编的入门教程。

首先主要学习了汇编语言的基本知识,介绍了汇编的背景知识及由来,让我知道了汇编语言是处在机器语言和高级语言中间的一种低级语言。由于计算机能够直接识别的数据是由二进制数0和1组成的代码。所以用机器语言编写的程序是计算机惟一能够直接识别并执行的程序,而用其他语言编写的程序必须经过翻译才能变换成机器语言程序,为了克服机器语言的缺点,人们采用助记符表示机器指令的操作码,用变量代替操作数的存放地址等,这样就形成了汇编语言。 然后介绍了8086计算机组织,汇编的学习不仅仅是学习其语法,而更多的是学习计算机基本的体系结构,学到这还没见到很多的指令和语句,但这是学习汇编前必须要知道和掌握的,只有知道了汇编的实质、如何工作及一些基本概念,才能进行下一步的学习。直到后面终于学了80X86指令系统和寻址方式及后来的汇编语言格式,才真正进入了汇编的指令学习阶段,每一条指令的学习虽然简单但比较多,特别是有些指令的使用场合及错误用法等易犯错、易混淆,例如在编写数据传送指令时,目的操作数和源操作数的类型一定要匹配,CS不能作为目的操作数,offset后只能跟简单地址符号,等等。但总的归纳起来主要掌握三点:

1、要求指令操作数的寻址方式;2、指令对标志位的影响和标志位对指令的影响;

3、指令的执行时间,对可完成同样功能的指令,要选用执行时间短的指令。这样学习起来方便的多,也更容易理解记住,这为以后的学习做了铺垫。

汇编的基本指令学完后,就开始进行应用了,首先学习的是循环与分支程序设计,第一个例子是简单的加法计算,虽然简单,却让我有点恐惧,一个在C语言中只要三四句就解决的问题,用汇编却写了将近20句,且还没有输出,也就是不知道结果是否正确。后来学习了dos系统功能调用,知道02号功能可以输出加法的结果,于是使用了,但输出的却是一个ASCII码值,又需要进行二进制到十六进制的转换,当时觉得很困惑,不知道为什么要转换,我们输入的不就是十六进制吗,算出来应该还是十六进制啊?随着继续深入的学习,才彻底明白为什么要转换,同时也了解了计算机中对于数字运算是如何工作的。这时发现汇编有很多高级语言所没有的优点,它能让我们更加了解计算机内部的组织结构,对我们计算机专业的学生来说,学习汇编也是提升综合能力的关键环节。一旦对它的原理掌握后,编写程序就容易多了。后来学的越多,越复杂,程序也是越来

越长,一堆的跳转指令,觉得很麻烦,且感觉整个程序无秩序,有时对于一段程序实现的功能还要研究半天。直到学习了子程序设计,一个过程定义对应一个功能,就像C语言中的函数,很有条理性。子程序设计能让一个大程序分成几个模块来做,提供了模块化程序设计的条件,可以节省存储空间及程序设计所花的时间,并且在主程序中进行call调用,十分方便,便于以后的维护、调试和修改。

最后学习了部分宏汇编,只是简单的几个用法并没有深入,但已经为我们做好了基础工作,便于我们自学后面的部分。宏(或宏指令)是源程序中一段有独立功能的程序代码,只需定义一次,可以多次调用。这似乎和子程序结构很像,但子程序有自己的优缺点,优点很明显,缺点是子程序为转子及返回、保存及恢复寄存器以及参数的传送等都要增加程序的开销,这些操作所消耗的时间以及它们所占用的存储空间,都是为取得子程序结构使程序模块化这一优点而增加的额外开销。所以,有时,特别在子程序本身较短或者是需要传送的参数较多的情况下,使用宏汇编更加有利。当然,在程序较复杂,实现的功能较多的情况下,子程序也必不可少。我的理解是:子程序是调用,而宏是替换,比如一个MAX宏,所有出现MAX的地方,都用宏代码代替。两者各有利弊,在掌握深入的基础上结合使用更好。

还有一点十分重要,和所有的程序设计语言一样,要学好汇编语言,实验是必不可少的环节。我深有体会:书上的程序都能看懂,基本原理也都明白,但是在自己亲手编写程序时,却无从下手,甚至连第一句该怎么写都不知道。后来随着老师的讲解和实验的进行,知道了程序的编写格式,包括数据段、堆栈段和代码段,其中数据段和堆栈段可以不定义,但代码段是必不可少的,也掌握了该怎么调试程序、运行程序等。特别是debug命令的使用,可以配合与list文件的使用,让我们可以调试排错、检查结果是否正确等,掌握debug的使用对实验有很大的帮助。程序的编写在记事本中进行即可,再在mask中编译,link中连接运行,当然也可以在专门的汇编工具中进行。通过实验,可以在很大程度上加深印象,在书上看程序,一切都是理所当然,十分顺利,而自己动手,才会真正发现自己的不足之处。

汇编语言作为一门计算机语言,有着不可替代的作用。我们要向学好它就必须要面对它,主动地学习,尤其是自己要经常地上机编程调试才能提升自己的能力。

 

第二篇:c语言总结

[原创]C语言总结

总算把C语言又看了一遍,总结如下:

1. 二制数中原码.反码.补码以及进制之间的转换:

原码:由符号位和该数的绝对值的二进制数组成.
反码:负数的反码为除符号位以外所有位均取反的结果.正数
的反码与原码相同,其补码也一样,后面不说了.
补码:负数的补码是在其反码的基础之上加1;
下面以-123为例求其各码:
原码:符号位为1,二进制数为1111011,(其转换参考下面进制的转换)所以其原码为11111011.
反码:10000100
补码:10000101
进制的转换:
十进制数转其他:
(1):整数:以十进制数123转换为八进制数为例:
123/8=15……3 ----------最低位
15/8=1………7
1/8=0………1 -----------最高位
结果就是173(从下到上),商为0止
(2):小数:0.325转换为二制数为例:
乘2 纯小数部分 整数部分
2 * 0.375=0.750 0.750 0
2 * 0.750=1.5 0.5 1
2 * 0.5 =1.0 0 1
结果就为0.011(从上到下),纯小数为0终止.否则一直进行下去
直到字节数已满.
其它转十进制:以十六进制数A5FE转换十进制数为例:
A5FE=A * 16^3+5 *16^2+F * 16^1+E=42494
二进制数:
十进制数不用说了,转八进制数时,从低位起,每三位对一位,不足补0;转十六进制数,从低位起每四位对一位,不足补0;其它转二进制数是一个相反的过程.
下面举两个例子:
(1);二进制数10101101转八进制数:
010 101 101
| | |
2 5 5
结果就是255
(2):十六进制A69E数转二制数:
A 6 9 E
| | | |
1010 0110 1001 1110
结果就是1010011010011110

2. 变量在内在中的存放与转换.

(1) 存放:
整 型数据是转换成相应的补码后直接存放在内存中,而实型与整型的存放不同,它是以指数形式存放,即符号位+小数部分+指数部分.比如:12345在内在中的 存放形式是这样的:第一位符号位是’+’,接下来存放的是小数,即0.12345,最后是指数5,而小数部分和指数部分所占的位数因编译系统的不同而不 同,不必深究,
(2) 转换:
所有可以转换的数据类型之间的转换都遵循一个规则:按存储单元的存储形式直接传送,从低位开始.比如:将十进制数-123转换为八进制数: 将其补码原样传送由于八进制数无符号(十六进制数也一样),所以最高位的1在八进制数的内在单元中已不代表符号,而代表数值进行运算.不同的编译器和机器 所得的结果不一定相同,因为整型变量所占的字节数不同,现以十六位机(另外还与编译器有关,假如整型占两个字节)为例:-123的补码为 1111111110000101,将其换算成八进制数为177605,而在32位机上(假如整形占4个字节),其结果就是37777777605.
实型转换成整型时,得到的绝不是你想要的结果,因为实型的存储形式是按指数形式存储的,低位中存储的是指数部分,当传送的时候,只是将指数部分或指数部分加上小数部分的小部分传送给整型变量,得到的结果不可能是你想要的结果.

3.字符----- ‘\’的作用:

与 一些字母组成转义字符,比如\t、\n之类的,与数字组成代表八进制数.比如:\123代表八进制数123即十进制数83.另外说明一下\r,其作用是将 当前位置移到本行开头,后面再输入字符时,原有的字符将会被覆盖,比如printf(“abcd\r \n“);将会输出” cd”,而不是” abcd”.还有\b也是一样.

4.自增自减:

(1).运算符在前时,先进行运算再进行取值,运算符在后时,先进行取值再进行运算.比如a=++i ;相当于i=i+1;a=i ; ,而a=i++;则相当于a=i;i=i+1;
(2).自增自减运算符不能用于常量 (表达式结果也是常量),只能用于变量.
(3).警告:不要使用+++,---之类的运算符,不同的编译器有不同的结果,也不要在一个式子中对同一变量进行多次++或--,比如:(i++)+(i++)+(i++),同样不同的编译器会得到不同的结果.

5.逗号运算符.

结合方向是自左向右,结果为最后一个表达式的值,其优先级最低.注意函数中的”,”一般是参数分隔符,不是逗号运算符,详情见44楼:
http://bbs.bc-cn.net/dispbbs.asp?boardid=5&replyid=62343&id=124695&page=1&skin=0&star=3

6.退出过程.

(1)continue :用于结束某次循环继续下一循环.
(2)break: 用于结束循环或结束switch语句.
(3)return: 用于结束某函数.
(4)exit: 用于结束某一程序

7.printf("%*s\n",M,"字符串"+N)的用法说明

先看N的值,去掉字符串的左边N个字符,再看字符串的位数与M的值的大小
1.若字符串的位数比M大,然后输出
2.若字符串的位数比M小,就先在M的左边补空格,使字符串的长度等于M,然后输出
printf("%-*s\n",M,"字符串"+N),
先看N的值,去掉字符串的左边N个字符,再看字符串的位数与M的值的大小
1.若字符串的位数比M大,然后输出
2.若字符串的位数比M小,就先在M的右边补空格,使字符串的长度等于M,然后输出

8.scanf函数的用法和说明

(1),指定输入列数,系统自动截取,比如:scanf(“%3d”,&a);输入1234;a=123;
(2).*的用法,跳过指定列数.比scanf(“%2d%*3d%d”,&a,&b);输入1234567,a=12,b=67;345被跳过
(3).输入时不能指定精度
(4). 输入数据时要与格式控制保持一致,格式控制中用”,”分开,输入时也要用”,”分开,格式控制中用”:”分开,输入时也要用”:”分开, 否则结果不可预料.如果格式控制中没有用任何字符隔开,你也不要用任何字符隔开,包括空格,比 如:scanf(“%c%c”,&a,&b);如果输入a b (中间有空格),此时a=’a’,b=’’,而b却存入缓存中.另外格式控制后是变量地址,普通变量不要忘了取地址运算符”&”.本来代表地址的 也不要多加”&”.比如指针(数组名也是指针)不用加”&”.
(5).清除缓存.当缓存中有数据时,使用scanf时,不会提示 输入字符,而是直接将缓存中的数据(包括回车符)赋给变量,直到缓存中没有变量.这样就要在调用scanf之前清除缓存,用语句 fflush(stdin);来清除缓存.另外用scanf(“ %c”,&a);在格式控制中多加一个空格可以清除一个字符,当有多个字符时就不有完全清除,还可以用 * 来清除缓存,和空格作用差不多,比如:scanf(“%*5c%c”,&a);可以清除缓存中五个字符.最好是直接用fflush (stdin);

9.易错点

(1).if (a=4)…; 相当于a=4;if(4)…;
(2).switch语句要注意break;
(3).do {…} while; 要注意最后一个分号不能丢
(4).不能定义动态数组,比如:scanf (“%d”,&n); int a[n];

10.void的说明.

Void代表空类型,在定义指针变量或函数时可以定义为void型,定义指针变量后可以在用的时候通过强制类型转换使其指向任何类型的数据.定义函数时,只是说明不能有返回值.如果函数中出现return就会报错.

11.局部变量.全局变量

作用域:局部变量的作用域从定义处到该过程(可以是一个复合语句也可以是一个函数)结束.全局变量的作用域从定义处到文件结束.
存在性:局部变量(未声明为static类型)当所在过程被调用时存在,结束后释放,如果定义为static就会一直存在直到程序结束,但其作用域不受影响.全局变量在被定义后就一直存在.直到程序结束.
优 先级:当两个相同变量的作用域重复(一个包含另一个),在较小的作用域范围内,较大作用域的那个变量被屏蔽.比如:i被定义为一个全局变量,在其作用域内 又定义了一个局部变量i,在局部变量i作用域内,全局变量i被屏蔽.又如.在一个函数中定义了一个局部变量i,而在该函数的某个复合语句中又定义了一个变 量i,则在该复合语句中局部变量i将被屏蔽.

12.预编译处理命令

#define:宏定义只是在编译前对代码作简单的字符串替换,不会考虑任何错误.宏定义不是语句,后面不要加";".
#include:
“ ”与< >之前的区别.” “是从用户当前目录寻找包含文件,若找不到就会到库函数所在目录中寻找,再找不到就报错,而< >则是直接在库函数所在目录中寻找,找不到报错.

13.指针:

(1).指针的加减法:指针的加减法不是作简单的加减,而是以指针变量所占的字节数为单位进行加减.
(2).数组名是指针常量,不能改变其值,比如数组a[ ],如果进行a++;就会报错
(3). 虽然指针变量中存放的地址是整型数据,但不能将整型数据直接赋值给指针变量,应该这样(假如p为int *型),p=(int *)1000;但禁用些法,因为你不知道1000这个单元有没有被其它单元占用,后果不可预料,同样也不能将一个指针变量的值直接赋给整形变量,也要进行 强制类型转换.
(4)定义指针后,在使用之前一定要先给它赋初值,切记
(5).二维数组中指针问题(int a[3] [4]),数组名a是一个指向行的指针(指向数组),而在其前面加一个 * ,*a就是指向列的指针(指向无素).a与*都是指向a[0][0];但a+1(行指针)指向a[1][0];而*a+1(列指针,和*(a+0)+1一 样)却指向a[0][1];同样在a+1前加一个*就又变成列指针了,*(a+1)+2就指向a[1][2].
(6),复杂类型的说明:从变量名处起,根据运算符优先级结合,一步一步分析,下面以一个比较复杂的类型( int * (*p(int))[ ] )为例:
第 一步,p先与()结合,说明是一个函数,第二步,()内有一个int,说明函数有一个形参为int型,第三步与*结合,说明返回的是一个指针变量,第四步 与[ ]结合,说明该指针变量指向数组,第五步再与*结合,说明数组中的元素为指针型,第六步说明数组中的指针元素的类型为int型,完毕,所以这是一个返回一 个由整型指针变量组成的数组的指针变量的函数.

14枚举类型:

枚举元素为常量,只有在定义的时候能对它们进行赋值(不赋值时,系统给它们赋值,从0开始递增),在其它时候均不能进行赋值,


大家有好的经验发上来,我加到里面去,如有错误请指示

相关推荐