Java 从内存剖析多态性?C51语言中为什么需要包含头文件

本文目录
Java 从内存剖析多态性
变量在类加载的时候开始初始化,肯定是父类变量先进入内存
方法调用时先从本类寻找,寻找不到再从父类寻找,本类同名方法进去内存,父类同名方法就不会进入内存,所以就覆盖了
C51语言中为什么需要包含头文件
我来回答你的问题吧,前几天对这个方面有一定的深入了解,也写下了大量的笔记
虽然C编程的时候,对于不同的芯片,有不同的头文件,但是,万变不离其宗。
只要学会了写自己的头文件,就可以应付各类型号单片机了,就算你用的是AT89C2052,还是AT89C51,STC12C等等,都可以用一个头文件reg51.h 不过要做相应的修。
以下是我对reg51.h个人的见解:(对于你很有用的) 后面带上了在编写C51时带用的头文件,及其内部函数和宏定义的详细解说。
想了解如下方面的知识来来邮amwjie72@163.com
一, C51内存结构深度剖析
二, reg51.头文件剖析
三, 浅淡变量类型及其作用域
四, C51常用头文件
五, 浅谈中断
六, C51编译器的限制
七, 小淡C51指针
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
reg51.头文件剖析
我们平时写单片机应用程序的时候,所使用的头文件大多都是用的的reg51.h或是用reg52.h。会写C51的人都会用,但对其头文件内部的定义有所了解的人确并不多。
下面对其内部做详细解释,方便读者作进一步的了解,并能运用各类型号的单片机。因为增强型号的单片机的增强功能都是通过特殊功能寄存器控制。
打开 reg52.h 头文件,会发现是由大量的 sfr ,sbit的声明组成,甚至于还有sfr16.其实这样的声明都是与单片机内部功能寄存器(特殊功能寄存器)联系起来的,下面对其做出详细解释
sfr: 声明变量
SFR 声明一个变量,它的声明与其它的C变量声明基本相同,唯一的区别,SFR在声明的同时为其指定特殊功能寄存器作为存储地址,而不同于C变量声明的整型,字符型等等由编译器自动分配存储空间。
如reg52.h头文件,第一条声明就是sfr P0 = 0x80;
此处声明一个变量P0,并指定其存储地址为特殊功能寄存器0x80;,在加入reg52.h头文件后。编写应用程序时P0就可以直接使用而无需定义,对P0的操作就是,对内部特殊功能寄存器(0x80对应用MCU的P0口)的操作,可进行读写操作。
如果将第一条声明改为sfr K0 = 0x80; 那么,如果要把单片机的P0口全部拉低,则不能写P0=0x00;而应保存后再在应用程序中写成K0=0x00;否则编译器会提示“P0为未定义标识符”
使用方法:
sfr //为变量分配一个特殊功能寄存器。
1 等号右边,只能是十进制,十六进制整型的数据常量,,不允许带操作符的表达式
经典的8051内核支持的SFR地址从0x80H~0xFF 飞利浦80C51MX系列0x180H~0x1FF
2 SFR不能声明于任何函数内部,包括main函数。只能声明于函数外。
3 用SFR声明一个变量后,不能用取地址运算符&获取其地址, 编译无法通过,编译器会提示非法操作。
4 有一点须特别注意,51内核0x80~0xff,为特殊功能寄存器地址区间,但并不是所有的地址都有定义,如果说你所用的MCU芯片上对于某个地址没有定义,那么用sfr在定义变量的时候,不要把变量的地址分配到未定义的特殊功能寄存器上,虽然编译时能通过,用KEIL仿真时貌似是没有问题,但下载到芯片里运行时,是会出问题的。比如说,向一个未定义的特殊功能寄存器执行读操作,读出来的就是一个未知的数。(读者可自行测试,先把串口通信调通,然后做一个简单的人机交互。读出一个数后,再发给计算机,用串口调试助手或是串口监控查看。这用方法在仿真的时候很有用。)所以具体那些特殊功能寄存器能够用,就要查看你使用的芯片手册。
5 若遇到增强性的单片机,只要知道其扩展的特殊功能寄存器的地址,用SFR定
就可以很方便进行编程。
sbit: 声明变量
sbit 同样是声明一个变量,和SFR 使用方法类似,但是SBIT是用来声明一个位变量,因为,在51系列的应用中,非常有必要对SFR的单个位进行存取,而通过bit 数据类型,使其具备位寻址功能。
如,在reg52.h中有如下声明
sfr IE = 0xA8;
sbit EA = IE^7;
sbit ET2 = IE^5; //8052 only
sbit ES = IE^4;
sbit ET1 = IE^3;
sbit EX1 = IE^2;
sbit ET0 = IE^1;
sbit EX0 = IE^0;
所以,对EA的操作即是对IE最高位的操作。
但如果想让 SP DPL DPH PCON TMOC TL0 TL1 TH0 TH1 SBUF这些特殊功能寄存器具备位寻址,采用上述如IE类似的定义,是不行的,虽然修改后,在编译的时候不会出现错误,但只要用到你定义的位变量名时就会出错。原因是,只有特殊功能寄存器的地址是8的倍数(十六进制以0或8结尾)才能进行位寻址。
打开reg52.h头文件可以看到,所有用sbit声明了的特殊功能寄存器的地址均是以0或8结尾
如硬要达到上述要求,可用带参的宏定义来完成。此处不做详细说明(意义并不大)。
下面对sbit的使用做详细介绍:
随着8051的应用,非常有必要对特殊功能寄存器的单个bit位进行存取,C51编译器通过sbit 数据类型,提供了对特殊功能寄存器的位操作。
以下是sbit的三种应用形式:
一, sbit name = sfr-name^bit-position;
sfr PSW =0xD0;
sfr IE =0xA8;
sbit OV= PSW^2;
sbit CY=PSW^7;
sbit EA= IE^7;
二, sbit name= sft-address^bit-position;
sbit OV =0xD0^2;
sbit CY =0xD0^7;
sbit EA =0xA8^7;
三, sbit name= sbit-address;
sbit OV =0xD2;
sbit CY =0xD7;
sbit EA =0xAF;
现对上述三种形式的声明做必要的说明
第一种形式sbit name = sfr-name^bit-position;如sbit OV= PSW^2; 当中的这个特殊功能寄存器必须在此之前已经用sfr 定义,否则编译会出错。
bit-position范围从0~7;
第二种形式 sbit name= sft-address^bit-position如sbit OV =0xD0^2; 与第一种形式不同之外在于,此处直接使用PSW的地址.第一种形式须先定义PSW
第三种形式. sbit name= sbit-address 如sbit OV =0xD2 是直接用的OV的地址
OV的地址计算方式,是OV所在的寄存器地址加上OV的bit-position
注意:
不是所有的SFR都可位寻址。只有特殊功能寄存器的地址是8的倍数(十六进制以0或8结尾)才能进行位寻址,并且sbit声明的变量名,虽可以是任意取,但是最好不要以下划线开头,因为以下划线开头的都保留给了C51的头文件做保留字。
sfr16: 声明变量
许多8051的派生型单片机,用两个连续地址的特殊功能寄存器,来存储一个16bit的值。例如,8052就用了0xCC和0xCD来保存定时/计数寄存器2的高字节和低字节。编译器提供sfr16这种数据类型,来保存两个字节的数据。虚拟出一个16bit的寄存器。
如下:
sfr16 T2 = 0xCC
存储方面为小端存储方式,低字节在前,高字节在后。定义时,只写低字节地址,如上,则定义T2为一个16位的特殊功能寄存器。 T2L= 0CCh, T2H= 0CDh
使用方法:
sfr
1 等号右边,只写两个特殊功能寄存器的低地址,且只能是十进制,十六进制的整型数据常量,不允许带操作符的表达式
2 SFR不能声明于任何函数内部,包括main函数。只能声明于函数外。
3 用SFR声明一个变量后,不能用取地址运算符&获取其地址, 编译无法通过,编译器会提示非法操作。
4 当你向一个sfr16写入数据的时候,KEIL CX51 编译器生成的代码,是先写高字节,后写低字节,(可通过返汇编窗口查看)在有些情况下,这并非我们所想要的操作顺序。使用时,须注意。
5 当你所要写入sfr16的数据,当是高字节先写还是低字节先写非常重要的时候,就只能用sfr 这个关键字来定义,并且任意时刻只保存一个字节,这样操作才能保证写入正确。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
C51常用头文件
在KEIL 中,对于单片机所使用的头文件,除了reg51 reg52以外,还有一些从各芯片制商的官网下载与reg51,reg52功能类似的头文件,需了解透外,还要对各类型单片机均可通用且相当有用的的头文件,做相应的了解。因为,内部所包含的函数与宏定义,可以及大的方便我们编写应用程序。
1字符函数 ctype.h
1 extern bit isalpha(char);
功能:检查参数字符是否为英文字母,是则返回1
2 extern bit isalnum(char)
功能:检查字符是否为英文字母或数字字符,是则返回1
3 extern bit iscntrl(char)
功能:检查参数值是否在0x00~0x1f 之间或等于0x7f,是则返回1
4 extern bit isdigit(char)
功能: 检查参数是否为数字字符,是则返回1
5 extern bit isgraph(char)
功能: 检查参数值是否为可打印字符,是则返回1,可打印字符为0x21~0x7e
6 extern bit isprint(char)
功能:除了与isgraph相同之外,还接受空格符0x20
7 extern bit ispunct(char)
功能:不做介绍。
8 extern bit islower(char)
功能:检查参数字符的值是否为小写英文字母,是则返回1
9 extern bit isupper(char)
功能:检查参数字符的值是否为大写英文字母,是则返回1
10 extern bit isspace(char)
功能:检查字符是否为下列之一,空格,制表符,回车,换行,垂直制表符和送纸。如果为真则返回1
11 extern bit isxdigit(char)
功能:检查参数字符是否为16进制数字字符,是则返回1
12 extern char toint(char)
功能:将ASCII字符0~9 a~f(大小写无关)转换成对应的16进制数字,
返回值00H~0FH
13 extern char tolower(char)
功能:将大写字符转换成小写形式,如字符变量不在A~Z之间,则不作转换而直接返回该字符
14 extern char toupper(char)
功能:将小写字符转换成大写形式,如字符变量不在a~z之间,则不作转换而直接返回该字符
15 define toascii(c) ((c)&0x7f)
功能:该宏将任何整形数值缩小到有效的ASCII范围之内,它将变量和0x7f相与从而去掉第7位以上的所有数位
16 #define tolower(c) (c-‘A’+’a’)
功能:该宏将字符与常数0x20 逐位相或
17 #define toupper(c) ((c)-‘a’+’A’)
功能:该宏将字符与常数0xdf 逐位相与
2数学函数 math.h
extern int abs (int val);
extern char cabs (char val);
extern long labs (long val);
extern float fabs (float val);
功能:返回绝对值。上面四个函数,除了形参和返回值不一样之外,
其它功能完全相同。
extern float exp (float val);
extern float log (float val);
extern float log10 (float val);
功能: exp 返回eval
log 返回 val 的自然对数
log10 返回 以10为底,val的对数
extern float sqrt (float val);
功能: 返回val的正平方根
extern int rand();
extern void srand(int n);
功能: rand返回一个0到32767之间的伪随机数,srand用来将随机数发生器初始化成一个已知的(期望)值。
Keil uVision3中的math.h库中,不包含此函数。
extern float sin (float val);
extern float cos (float val);
extern float tan (float val);
功能: 返回val的正弦,余弦,正切值。val为弧度 fabs(var) 《=65535
extern float asin (float val);
extern float acos (float val);
extern float atan (float val);
extern float atan2 (float y, float x);
功能: asin 返回val的反正弦值。acos 返回val的反余弦值。
atan 返回val的反正切值。
asin atan acos的值域均为 -π/2~+π/2
atan2返回x/y,的反正切值,其值域为-π~+π
extern float sinh (float val);
extern float cosh (float val);
extern float tanh (float val);
功能:cosh返回var的双曲余弦值,sinh返回var的双曲正弦值,
tanh返回var的双曲正切值。
extern float ceil (float val);
功能: 向上取整,返回一个大于val的最小整数。
extern float floor (float val);
功能: 向下取整,返回一个小于val的最大整数。
extern float pow (float x, float y);
功能: 计算计算xy的值。当(x=0,y《=0)或(x《0.y不是整数)时会发生错误。
extern void fpsave(struct FPBUF *p)
extern void fprestore(struct FPBUF *p)
功能:fpsave 保存浮点了程序的状态,fprestore恢复浮点子程序的原始状态,当中断程序中需要执行浮点运算时,这两个函数是很有用的。
注: Keil uVision3中的math.h库中,不包含此函数。
3绝对地址访问 absacc.h
#define CBYTE ((unsigned char volatile code *) 0)
#define DBYTE ((unsigned char volatile data *) 0)
#define PBYTE ((unsigned char volatile pdata *) 0)
#define XBYTE ((unsigned char volatile xdata *) 0)
功能:CBYTE 寻址 CODE区
DBYTE 寻址 DATA区
PBYTE 寻址 XDATA(低256)区
XBYTE 寻址 XDATA区
例: 如下指令在对外部存储器区域访问地址0x1000
xvar=XBYTE;
XBYTE=20;
#define CWORD ((unsigned int volatile code *) 0)
#define DWORD ((unsigned int volatile data *) 0)
#define PWORD ((unsigned int volatile pdata *) 0)
#define XWORD ((unsigned int volatile xdata *) 0)
功能:与前面的一个宏相似,只是它们指定的数据类型为unsigned int .。
通过灵活运用不同的数据类型,所有的8051地址空间都是可以进行访问。
如
DWORD=0x12F8;
即内部数据存储器中(0x08)=0x12; (0x09)=0xF8
4 内部函数 intrins.h
extern unsigned char _cror_ (unsigned char var, unsigned char n);
extern unsigned int _iror_ (unsigned int var, unsigned char n);
extern unsigned long _lror_ (unsigned long var, unsigned char n);
功能:将变量var 循环右移 n 位。
上三个函数的区别在于,参数及返回值的类型不同
extern unsigned char _crol_ (unsigned char var, unsigned char n);
extern unsigned int _irol_ (unsigned int var, unsigned char n);
extern unsigned long _lrol_ (unsigned long var, unsigned char n);
功能:将变量var 循环左移 n 位。
上三个函数的区别在于,参数及返回值的类型不同
例如:
#include《intrins.h》
void main()
{
unsigned int y;
y=0x0ff0;
y=_irol_(y,4); //y=0xff00
y=_iror_(y,4); //y=0x0ff0
}
void _nop_(void);
功能:_nop_产生一个8051单片机的NOP指令,C51编译器在程序调用_nop_ 函数的地方,直接产生一条NOP指令。
另外,站长团上有产品团购,便宜有保证
C语言源程序文件、目标文件和可执行文件的扩展名是什么
C语言源程序文件扩展名:.c
目标文件扩展名:.obj
可执行文件扩展名:.exe
源程序:程序可以用高级语言或汇编语言编写,用高级语言或汇编语言编写的程序称为源程序。C语言源程序的扩展名为“.c”。源程序不能直接在计算机上执行,需要用“编译程序”将源程序编译为二进制形式的代码。
目标程序:源程序经过“编译程序”编译所得到的二进制代码称为目标程序。目标程序
的扩展名为“.obj”。
目标代码尽管已经是机器指令,但是还不能运行,因为目标程序还没有解决函数调用问题,需要将各个目标程序与库函数连接,才能形成完整的可执行程序。
可执行程序:目标程序与库函数连接,形成的完整的可在操作系统下独立执行的程序
称为可执行程序。可执行程序的扩展名为“.exe“。
***隐藏网址***
扩展资料:
C语言创建程序的步骤:
:就是创建和修改C程序的源代码-我们编写的程序称为源代码。
编译:就是将源代码转换为机器语言。编译器的输出结果成为目标代码,存放它们的文件称为目标文件。扩展名为.o或者.obj。(该部分编译是指汇编器编译汇编语言或者编译器编译高级语言)
链接:链接器将源代码由编译器产生的各种模块组合起来,再从C语言提供的程序库中添加必要的代码模块,将它们组成一个可执行的文件。在windows下扩展名为.exe,Unix下无扩展名。
执行:运行程序。
参考资料:
IT专家网——C语言编程程序编译全过程剖析
全面剖析C#接口编程之定义接口
从技术上讲 接口是一组包含了函数型方法的数据结构 通过这组数据结构 客户代码可以调用组件对象的功能
定义接口成员接口可以包含一个和多个成员 这些成员可以是方法 属性 索引指示器和事件 但不能是常量 域 操作符 构造函数或析构函数 而且不能包含任何静态成员 接口定义创建新的定义空间 并且接口定义直接包含的接口成员定义将新成员引入该定义空间 说明
· 接口的成员是从基接口继承的成员和由接口本身定义的成员
· 接口定义可以定义零个或多个成员 接口的成员必须是方法 属性 事件或索引器 接口不能包含常数 字段 运算符 实例构造函数 析构函数或类型 也不能包含任何种类的静态成员
· 定义一个接口 该接口对于每种可能种类的成员都包含一个 方法 属性 事件和索引器
· 接口成员默认访问方式是public 接口成员定义不能包含任何修饰符 比如成员定义前不能加abstract public protected internal private virtual override 或static 修饰符
· 接口的成员之间不能相互同名 继承而来的成员不用再定义 但接口可以定义与继承而来的成员同名的成员 这时我们说接口成员覆盖了继承而来的成员 这不会导致错误 但编译器会给出一个警告 关闭警告提示的方式是在成员定义前加上一个new关键字 但如果没有覆盖父接口中的成员 使用new关键字会导致编译器发出警告
· 方法的名称必须与同一接口中定义的所有属性和事件的名称不同 此外 方法的签名必须与同一接口中定义的所有其他方法的签名不同
· 属性或事件的名称必须与同一接口中定义的所有其他成员的名称不同
· 一个索引器的签名必须区别于在同一接口中定义的其他所有索引器的签名
· 接口方法声明中的属性(attributes) 返回类型(return type) 标识符(identifier)和形式参数列表(formal parameter lis)与一个类的方法声明中的那些有相同的意义 一个接口方法声明不允许指定一个方法主体 而声明通常用一个分号结束
· 接口属性声明的访问符与类属性声明的访问符相对应 除了访问符主体通常必须用分号 因此 无论属性是读写 只读或只写 访问符都完全确定
· 接口索引声明中的属性(attributes) 类型(type)和形式参数列表(formal parameter list)与类的索引声明的那些有相同的意义
下面例子中接口IMyTest包含了索引指示器 事件E 方法F 属性P这些成员
interface IMyTest{ string this { get; set; } event EventHandler E ; void F(int value) ; string P { get; set; }}public delegate void EventHandler(object sender EventArgs e) ;
下面例子中接口IStringList包含每个可能类型成员的接口 一个方法 一个属性 一个事件和一个索引
public delegate void StringListEvent(IStringList sender);public interface IStringList{ void Add(string s); int Count { get; } event StringListEvent Changed; string this { get; set; }}
接口成员的全权名使用接口成员也可采用全权名(fully qualified name) 接口的全权名称是这样构成的 接口名加小圆点 再跟成员名比如对于下面两个接口
interface IControl { void Paint( ) ;}interface ITextBox: IControl { void GetText(string text) ;}
其中Paint 的全权名是IControl Paint GetText的全权名是ITextBox GetText 当然 全权名中的成员名称必须是在接口中已经定义过的 比如使用ITextBox Paint 就是不合理的
如果接口是名字空间的成员 全权名还必须包含名字空间的名称
namespace System{ public interface IDataTable { object Clone( ) ; }}
那么Clone方法的全权名是System IDataTable Clone
定义好了接口 接下来我们关心的就是怎样实现对接口的访问 这部分内容 我将在下一篇文章中和您进一步探讨
定义接口的一般形式为
说明
· attributes(可选) 附加的定义性信息
· modifiers(可选) 允许使用的修饰符有new和四个访问修饰符 分别是 new public protected internal private 在一个接口定义中同一修饰符不允许出现多次 new修饰符只能出现在嵌套接口中
表示覆盖了继承而来的同名成员 The public protected internal and private修饰符定义了对接口的访问权限
· 指示器和事件
· identifier 接口名称
· base list(可选):包含一个或多个显式基接口的列表 接口间由逗号分隔
· interface body 对接口成员的定义
· 接口可以是命名空间或类的成员 并且可以包含下列成员的签名 方法 属性 索引器
· 一个接口可从一个或多个基接口继承
接口这个概念在C#和Java中非常相似 接口的关键词是interface 一个接口可以扩展一个或者多个其他接口 按照惯例 接口的名字以大写字母 I 开头 下面的代码是C#接口的一个例子 它与Java中的接口完全一样
interface IShape { void Draw ( ) ;}
如果你从两个或者两个以上的接口派生 父接口的名字列表用逗号分隔 如下面的代码所示
interface INewInterface: IParent IParent { }
然而 与Java不同 C#中的接口不能包含域(Field) 另外还要注意 在C#中 接口内的所有方法默认都是公用方法 在Java中 方法定义可以带有public修饰符(即使这并非必要) 但在C#中 显式为接口的方法指定public修饰符是非法的 例如 下面的C#接口将产生一个编译错误
interface IShape { public void Draw( ) ; }
下面的例子定义了一个名为IControl 的接口 接口中包含一个成员方法Paint
interface IControl {void Paint( ) ;}
在下例中 接口 IInterface从两个基接口 IBase 和 IBase 继承
interface IInterface: IBase IBase { void Method ( ) ; void Method ( ) ;}
接口可由类实现 实现的接口的标识符出现在类的基列表中 例如
class Class : Iface Iface { // class 成员 }
类的基列表同时包含基类和接口时 列表中首先出现的是基类 例如
class ClassA: BaseClass Iface Iface { // class成员 }
以下的代码段定义接口IFace 它只有一个方法
interface IFace { void ShowMyFace( ) ;}
不能从这个定义实例化一个对象 但可以从它派生一个类 因此 该类必须实现ShowMyFace抽象方法
class CFace:IFace{ public void ShowMyFace( ) { Console WriteLine( implementation ) ; } }
基接口一个接口可以从零或多个接口继承 那些被称为这个接口的显式基接口 当一个接口有比零多的显式基接口时 那么在接口的定义中的形式为 接口标识符后面跟着由一个冒号 : 和一个用逗号 分开的基接口标识符列表
接口基 接口类型列表说明
· 一个接口的显式基接口必须至少同接口本身一样可访问 例如 在一个公共接口的基接口中指定一个私有或内部的接口是错误的
· 一个接口直接或间接地从它自己继承是错误的
· 接口的基接口都是显式基接口 并且是它们的基接口 换句话说 基接口的集合完全由显式基接口和它们的显式基接口等等组成 在下面的例子中
interface IControl { void Paint( ) ;}interface ITextBox: IControl { void SetText(string text) ;}interface IListBox: IControl { void SetItems(string items) ;}interface IComboBox: ITextBox IListBox { }
IComboBox 的基接口是IControl ITextBox 和 IlistBox
· 一个接口继承它的基接口的所有成员 换句话说 上面的接口IComboBox就像Paint一样继承成
员SetText 和 SetItems
· 一个实现了接口的类或结构也隐含地实现了所有接口的基接口
接口主体一个接口的接口主体定义接口的成员
lishixinzhi/Article/program/net/201311/11751
更多文章:
全球新冠肺炎疫情背景下航运发展(盐田港复苏日志:半年历劫从“低谷”到“爆仓” 疫情之后巨轮如何越洋航行)
2026年9月7日 17:10
matlab求解带字母参数方程组(我想matlab求一个关于x,y的方程组 ab c d f e h m n 都是参数)
2026年9月7日 16:30
oracle中的循环语句(下面哪个不是oracle程序设计中的循环语句 a for)
2026年9月7日 15:30
电脑里2个系统怎么删除一个(电脑开机显示有两个系统,如何删除一个)
2026年9月7日 12:20
scrollthrough意思(“scroll”是什么意思)
2026年9月7日 08:00
怎么激活keygen(注册机如何激活cad2008一个简单激活cad2008的方法)
2026年9月7日 06:30
vba编写excel插件(excel vba中能否动态创建控件)
2026年9月7日 04:40





