为什么单片机51汇编程序,累加器有时候要写成ACC,有时候却要写成A 。否则都会报错

为什么单片机51汇编程序,累加器有时候要写成ACC,有时候却要写成A 。否则都会报错,第1张

这是51的系统架构决定的。因为51累加器有2个地址,一是特殊功能寄存器地址,指令使用这个地址访问累加器,是已明确知道访问对象就是累加器,是专指的,这是用A表示。比如ADD A,03H,因为在51中,ADD 的第一对象就是累加器,而不能用别的寄存器,用A可以少打俩字母CC。

另外一个是累加器的直接内存地址,指令访问时并不明确访问对象是什么,因为访问地址是程序员编程决定的。比如PUSH/POP指令,在51的定义里是PUSH/POP direct,这个direct可以是0~255。指令事前并不知direct到底是多少,这时将direct写成ACC,编译器就找到默认的地址E0H,而将它编译出来。

如果你熟悉51单片机,应不会有这样的疑问。不过,不管是否熟悉51系统,开始时尽管讲累加器些成A,而不写成ACC。当编译器提示出错时,将A 改成ACC即可。所以这样做的原因,是因为大多数51中访问特殊功能寄存器的速度要比访问直接地址内存快,特别累加器的特殊功能寄存器地址,访问速度时最快的。

类似的情况还存在通用寄存器组R0~R7上。它们跟累加器一样同时有寄存器地址和直接内存地址,有的编译器如果 Keil 将它们的直接内存地址写成AR0~AR7。访问寄存器地址也比访问内存地址快。

代码就是程序员用开发工具所支持的语言写出来的源文件

代码是一组有序的数字或字母的排列,是代表客观实体及其属性的符号。

代码设计的原则包括惟一确定性、标准化和通用性、可扩充性与稳定性、便于识别与记忆、力求短小与格式统一以及容易修改等。

代码可以泛指,如所有编程语言所编写的字符都可以叫代码!

例如生活中:

有些人家用

老大,老二,老三,老夭,来代替家中四兄弟姐妹

老大,老二,老三,老夭

就是代码,代替四个名字,也代替四个人老妈喊,"老夭,来淘米",就用了代码老夭

例如:ASCII码,

GB2312码,

UTF-8码,

电报码,

区位码

html代码,js代码,css代码。

这些都是数字码

PUSH,

POP,

ADD

这些是运算和 *** 作码

PUSH,

POP

是堆栈推入d出 *** 作,

ADD

是加法运算

堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除 *** 作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。

向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

扩展资料:

一、堆的算法思想

不必将值一个个地插入堆中,通过交换形成堆。假设根的左、右子树都已是堆,并且根的元素名为R。这种情况下,有两种可能:

(1) R的值小于或等于其两个子女,此时堆已完成。

(2) R的值大于其某一个或全部两个子女的值,此时R应与两个子女中值较小的一个交换,结果得到一个堆,除非R仍然大于其新子女的一个或全部的两个。这种情况下,我们只需简单地继续这种将R“拉下来”的过程,直至到达某一个层使它小于它的子女,或者它成了叶结点。

二、栈的基本算法

1、进栈(PUSH)算法

①若TOP≥n时,则给出溢出信息,作出错处理(进栈前首先检查栈是否已满,满则溢出;不满则作②)。

②置TOP=TOP+1(栈指针加1,指向进栈地址)。

③S(TOP)=X,结束(X为新进栈的元素)。

2、退栈(POP)算法

①若TOP≤0,则给出下溢信息,作出错处理(退栈前先检查是否已为空栈, 空则下溢;不空则作②)。

②X=S(TOP),(退栈后的元素赋给X)。

③TOP=TOP-1,结束(栈指针减1,指向栈顶)。

参考资料来源:百度百科-堆

参考资料来源:百度百科-栈

python主要应用领域:

1、云计算:

PYTHON语言算是云计算最火的语言, 典型应用OpenStack。

2、WEB前端开发

python相比php\ruby的模块化设计,非常便于功能扩展;多年来形成了大量优秀的web开发框架,并且在不断迭代;如目前优秀的全栈的django、框架flask,都继承了python简单、明确的风格,开发效率高、易维护,与自动化运维结合性好。

python已经成为自动化运维平台领域的事实标准;众多大型网站均为Python开发,Youtube, Dropbox, 豆瓣。

3、人工智能应用

基于大数据分析和深度学习而发展出来的人工智能本质上已经无法离开python的支持,目前世界优秀的人工智能学习框架如Google的TransorFlow 、FaceBook的PyTorch以及开源社区的神经网络库Karas等是用python实现的。

甚至微软的CNTK(认知工具包)也完全支持Python,而且微软的Vscode都已经把Python作为第一级语言进行支持。

4、系统运维工程项目

Python在与 *** 作系统结合以及管理中非常密切,目前所有linux发行版中都带有python,且对于linux中相关的管理功能都有大量的模块可以使用,例如目前主流的自动化配置管理工具:SaltStackAnsible(目前是RedHat的)。

目前在几乎所有互联网公司,自动化运维的标配就是python+Django/flask,另外,在虚拟化管理方面已经是事实标准的openstack就是python实现的,所以Python是所有运维人员的必备技能。

5、金融理财分析

量化交易,金融分析,在金融工程领域,Python语言不但在用,且用的最多,而且重要性逐年提高。原因:作为动态语言的Python,语言结构清晰简单,库丰富,成熟稳定,科学计算和统计分析都很牛逼,生产效率远远高于c,c++,java,尤其擅长策略回测。

5、大数据分析

Python语言相对于其它解释性语言最大的特点是其庞大而活跃的科学计算生态,在数据分析、交互、可视化方面有相当完善和优秀的库(python数据分析栈:Numpy Pandas ScipyMatplotlipIpython)

并且还形成了自己独特的面向科学计算的Python发行版Anaconda,而且这几年一直在快速进化和完善,对传统的数据分析语言如R MATLAB SAS Stata形成了非常强的替代性。

参考资料:

百度百科_Python

许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数(alignment modulus)。 当一种类型S的对齐模数与另一种类型T的对齐模数的比值是大于1的整数,我们就称类型S的对齐要求比T强(严格),而称T比S弱(宽松)。这种强制的要求一来简化了处理器与内存之间传输系统的设计,二来可以提升读取数据的速度。比如这么一种处理器,它每次读写内存的时候都从某个8倍数的地址开始,一次读出或写入8个字节的数据,假如软件能保证double类型的数据都从8倍数地址开始,那么读或写一个double类型数据就只需要一次内存 *** 作。否则,我们就可能需要两次内存 *** 作才能完成这个动作,因为数据或许恰好横跨在两个符合对齐要求的8字节内存块上。某些处理器在数据不满足对齐要求的情况下可能会出错,但是Intel的IA32架构的处理器则不管数据是否对齐都能正确工作。不过Intel奉劝大家,如果想提升性能,那么所有的程序数据都应该尽可能地对齐。

Win32平台下的微软C编译器(clexe for 80x86)在默认情况下采用如下的对齐规则:任何基本数据类型T的对齐模数就是T的大小,即sizeof(T)。比如对于double类型(8字节),就要求该类型数据的地址总是8的倍数,而char类型数据(1字节)则可以从任何一个地址开始。Linux下的GCC奉行的是另外一套规则(在资料中查得,并未验证,如错误请指正):任何2字节大小(包括单字节吗)的数据类型(比如short)的对齐模数是2,而其它所有超过2字节的数据类型(比如Long和double)都以4为对齐模数。

现在回到我们关心的struct上来。ANSIC规定一种结构类型的大小是它所有字段的大小以及字段之间或字段尾部的填充区大小之和。填充区就是为了使结构体字段满足内存对齐要求而额外分配给结构体的空间。那么结构体本身也有对齐要求,ANSIC标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格(但此非强制要求,VC71就仅仅是让它们一样严格)。我们来看一个例子(以下所有试验的环境是Intel Celeron 24G + WIN2000 PRO +vc71,内存对齐编译选项是"默认",即不指定/Zp与/pack选项):

typedef struct ms1 { char a; int b; } MS1;

MS1中有最强对齐要求的是b字段(int),所以根据编译器的对齐规则以及ANSIC标准,该结构体的内存布局图如下:

这个方案在a与b之间多分配了3个填充(padding)字节,这样当整个struct对象首地址满足4字节的对齐要求时,b字段也一定能满足int型的4字节对齐规定。那么sizeof(MS1)显然就应该是8,而b字段相对于结构体首地址的偏移就是4。非常好理解,对吗?现在我们把MS1中的字段交换一下顺序:

typedef struct ms2 { int a; char b; } MS2;

或许你认为MS2比MS1的情况要简单,它的布局应该就是 因为MS2对象同样要满足4字节对齐规定,而此时a的地址与结构体的首地址相等,所以它一定也是4字节对齐。可是却不全面。让我们来考虑一下定义一个MS2类型的数组会出现什么问题。C标准保证,任何类型(包括自定义结构类型)的数组所占空间的大小一定等于一个单独的该类型数据的大小乘以数组元素的个数。换句话说,数组各元素之间不会有空隙。按照上面的方案,一个MS2数组array的布局就是:当数组首地址是4字节对齐时,array[1]a也是4字节对齐,可是array[2]a呢?array[3]a 呢?可见这种方案在定义结构体数组时无法让数组中所有元素的字段都满足对齐规定,必须修改成如下形式:

现在无论是定义一个单独的MS2变量还是MS2数组,均能保证所有元素的所有字段都满足对齐规定。那么sizeof(MS2)仍然是8,而a的偏移为0,b的偏移是4。尝试分析一个稍微复杂点的类型。 typedef struct ms3 { char a; short b; double c; } MS3; 我想你一定能得出如下正确的布局图: sizeof(short)等于2,b字段应从偶数地址开始,所以a的后面填充一个字节,而sizeof(double)等于8,c字段要从8倍数地址开始,前面的a、b字段加上填充字节已经有4 bytes,所以b后面再填充4个字节就可以保证c字段的对齐要求了。sizeof(MS3)等于16,b的偏移是2,c的偏移是8。接着看看结构体中字段还是结构类型的情况: typedef struct ms4 { char a; MS3 b; } MS4; MS3中内存要求最严格的字段是c,那么MS3类型数据的对齐模数就与double的一致(为8),a字段后面应填充7个字节,因此MS4的布局应该是: 显然,sizeof(MS4)等于24,b的偏移等于8。

在实际开发中,我们可以通过指定/Zp编译选项或者在代码中用#pragma pack指令来更改编译器的对齐规则。比如指定/Zpn(VC71中n可以是1、2、4、8、16)就是告诉编译器最大对齐模数是n。或者定义结构时

#pragma pack(push, n)

typedef struct ms3 { char a; short b; double c; } MS3;

#pragma pack(pop);

在这种情况下,所有小于等于n字节的基本数据类型的对齐规则与默认的一样,但是大于n个字节的数据类型的对齐模数被限制为n。如果n = 1,那么结构体的大小就是各个字段的大小之和,在Moses中定义结构体的地方随处可见,这样做可以减少结构体所占用的内存空间。

VC71的默认对齐选项就相当于/Zp8。仔细看看MSDN对这个选项的描述,会发现它郑重告诫了程序员不要在MIPS和Alpha平台上用/Zp1和/Zp2选项,也不要在16位平台上指定/Zp4和/Zp8(想想为什么?)。 结构体的内存布局依赖于CPU、 *** 作系统、编译器及编译时的对齐选项,而你的程序可能需要运行在多种平台上,你的源代码可能要被不同的人用不同的编译器编译(试想你为别人提供一个开放源码的库),那么除非绝对必需,否则你的程序永远也不要依赖这些诡异的内存布局。顺便说一下,如果一个程序中的两个模块是用不同的对齐选项分别编译的,那么它很可能会产生一些非常微妙的错误。如果你的程序确实有很难理解的行为,不防仔细检查一下各个模块的编译选项。

---------------------------------------------------------------------------------

问题:下面的试验,请问如何解释?

#pragma pack(push, 2)

struct s

{

char a;

};

#pragma pack (pop)

void TestPack()

{

s c[2];

assert(sizeof(s)==1);

assert(sizeof(c)==2);

}

int _tmain(int argc, _TCHAR argv[])

{

TestPack();

return 0;

}

解答:

每一种基本的数据类型都有该数据类型的对齐模数(alignment modulus)。Win32平台下的微软C编译器(clexe for 80x86)在默认

情况下: 任何基本数据类型T的对齐模数就是T的大小,即sizeof(T)。

一组可能的对齐模数数据如下:

数据类型 模数

------------------

char 1

shor 2

int 4

double 8

ANSI C规定一种结构类型的大小是它所有字段的大小以及字段之间或字段尾部的填充区大小之和。

注:填充区就是为了使结构体字段满足内存对齐要求而额外分配给结构体的空间。

产生填充区的条件:

当结构体中的成员一种类型S的对齐模数与另一种类型T的对齐模数不一致的时候,才可能产生填充区。

我们通过编译选项设置/zpn 或#pragma pack(push, n) 来设置内存对齐模数时,当结构体中的某中基本数据类型的对齐模数大于n时才会影响填充区的大小,否则将会按照基本数据类型的对齐模数进行对齐。

例子:

当n = 1时:

#pragma pack(push,1)

typedef struct ms3{char a; short b; double c; } MS3;

#pragma pack(pop)

这时n=1,此结构中基本数据类型short的对齐模数为2,double为8,大于n 所以将会影响这两个变量存储时地址的偏移量,必须是n的整数倍,而char的对齐模数是1,小于等于n,将会按照其自身的对齐模数1进行对齐

因为n=1,所以这三个变量在内存中是连续的而不存在填充区内存布局如下:

___________________________

| a | b | c |

+-------------------------+

Bytes: 1 2 8

sizeof(MS3) = 11

当n = 2时:

#pragma pack(push,2)

typedef struct ms3{char a; short b; double c; } MS3;

#pragma pack(pop)

这时n=2,此结构中基本数据类型double的对齐模数为8,大于n, 所以将会影响这个变量存储时地址的偏移量,必须是n的整数倍,而char 和 short 的对齐模数小于等于n, 将会按照其自身的对齐模数分别是1,2进行对齐内存布局如下:

____________________________

| a |\| b | c |

+---------------------------+

Bytes: 1 1 2 8

此时变量c的存储地址偏移是4,是n=2的整数倍,当然偏移为6,8等等时也满足这个条件,但编译器不至于愚蠢到这种地步白白浪费空间,呵。

sizeof(MS3) = 12

当n = 4时:与n=2时结果是一样的

当n = 8时:

#pragma pack(push,8)

typedef struct ms3{char a; short b; double c; } MS3;

#pragma pack(pop)

这时n=8,此结构中char ,short ,double的对齐模数为都,小于等于n,将会按照其自身的对齐模数分别是1,2,8进行对齐即:short变量存储时地址的偏移量是2的倍数;double变量存储时地址的偏移量是8的倍数

内存布局如下:

_______________________________________

| a |\| b |\padding\| c |

+-------------------------------------+

Bytes: 1 1 2 4 8

此时变量a的存储地址偏移是0,当然也是char型对齐模数1的整数倍了

变量b的存储地址偏移要想是short型对齐模数2的整数倍,因为前面a占了1 个byte ,所以至少在a 与b之间再加上1 个byte的padding才能满足条件。

变量c的存储地址骗移要想是double型对齐模数8的整数倍,因为前面a 和b 加 1个byte 的padding,共4 bytes所以最少还需要4 bytes的padding才能满足条件。

sizeof(MS3) = 16

当n = 16时:与n=8时结果是一样的

====================================================

根据上面的分析,如下定义的结构

#pragma pack(push, 2)

struct s

{

char a;

};

#pragma pack (pop)

因为char 的对齐模数是1,小于n=2,所以将按照自身的对齐模数对齐。根本就不会存在填充区,所以sizeof(s) = 1对于s c[2]; sizeof(c)==2 也是必然的。

再看下面的结构:

#pragma pack(push, n)//n=(1,2,4,8,16)

struct s

{

double a;

double b;

double c;

};

#pragma pack (pop)

对于这样的结构无论pack设置的对齐模数为几都不会影响其大小,即无padding

double 类型的对齐模数为8

当n<8时,虽然满足前面讲的规则:当结构体中的某中基本数据类型的对齐模数大于n时才会影响填充区的大小。但这个时候无论n等于几(1,2,4),double 变量存储时地址的偏移量都是n的整数倍,所以根本不需要填充区。当n>=8时,自然就按照double的对齐模数进行对齐了因为类型都一样所以变量之间在内存中不会存在填充区

---------------------------------------------------------------------------------------------------------------------

补充一点:

如果在定义结构的时候,仔细调整顺序,适当明确填充方式,则最终内存结果可以与编译选项/Zpn 或 pack无关。

举个例子:

typedef struct ms1{ char a; char b; int c; short d; } MS1;

在不同的 /Zpn下,sizeof(MS1)的长度可能不同,也就是内存布局不同。

如果改成

typedef struct ms2{ char a; char b; short d; int c; } MS2;

即便在不同的/Zpn或pack方式下,编译生成的内存布局总是相同的;

再比如:

typedef struct ms3{ char a; char b; int c; } MS3;

可以改写成:

typedef struct ms4{ char a; char b; short padding; int c; } MS4; 显式地写上 padding

(通过源代码本身来消除隐患,要比依赖编译选项更加可靠,并易于移植,优质的代码应该做到这一点)

(减少隐含padding的另外一个好处是少占内存,当结构的实例数量很大时,内存的节省量是非常可观的)

(以上的变量/结构命名没有遵循命名规范,只为说明用,不可模仿)

以上就是关于为什么单片机51汇编程序,累加器有时候要写成ACC,有时候却要写成A 。否则都会报错全部的内容,包括:为什么单片机51汇编程序,累加器有时候要写成ACC,有时候却要写成A 。否则都会报错、什么是代码,代码的作用是什么啊、什么是堆什么是栈啊等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9715079.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存