嵌入式常用宏定义(精)
- 格式:doc
- 大小:38.50 KB
- 文档页数:5
详解C语⾔的宏定义宏定义介绍假设我们有⼀个 C 源⽂件 main.c,那么只需要通过 gcc main.c -o main.exe 即可编译成可执⾏⽂件(如果只写 gcc main.c,那么 Windows 上会默认⽣成 a.exe、Linux 上会默认⽣成 a.out ),但是这⼀步可以拆解成如下步骤:预处理:gcc -E main.c -o main.i,根据 C 源⽂件得到预处理之后的⽂件,这⼀步只是对 main.c 进⾏了预处理:⽐如宏定义展开、头⽂件展开、条件编译等等,同时将代码中的注释删除,注意:这⾥并不会检查语法;编译:gcc -S main.i -o main.s,将预处理后的⽂件进⾏编译、⽣成汇编⽂件,这⼀步会进⾏语法检测、变量的内存分配等等;汇编:gcc -c main.s -o main.o,根据汇编⽂件⽣成⽬标⽂件,当然我们也可以通过 gcc -c main.c -o main.o 直接通过 C 源⽂件得到⽬标⽂件;链接:gcc main.o -o main.exe,程序是需要依赖各种库的,可以是静态库也可以是动态库,因此需要将⽬标⽂件和其引⽤的库链接在⼀起,最终才能构成可执⾏的⼆进制⽂件。
⽽这⾥我们主要来介绍⼀下预处理中的宏定义,相信很多⼈都觉得宏定义⾮常简单,但其实宏定义有很多⾼级⽤法。
我们先来看看简单的宏定义:#include <stdio.h>// 宏定义的⽅式为:#define 标识符常量// 然后会将所有的 PI 替换成 3.14#define PI 3.14int main() {printf("%f\n", PI);}我们⽣成预处理之后的⽂件:gcc -E main.c -o main.i我们看到 PI 被替换成了 3.14,当然除了浮点型之外,也可以是其它的类型:#include <stdio.h>#define NAME "satori"#define AGE 17#define GENDER 'f'int main() {printf("%s %d %c\n", NAME, AGE, GENDER); // satori 17 f}我们再来查看⽣成的预处理⽂件:我们看到确实只是简单替换,除此之外,没有做任何的处理。
实验一熟悉Linux开发环境一、实验目的1.熟悉Linux开发环境,学习Linux开发环境的配置和使用,掌握Minicom串口终端的使用。
2.学习使用Vi编辑器设计C程序,学习Makefile文件的编写和armv4l-unkonown-linux-gcc编译器的使用,以及NFS方式的下载调试方法。
3.了解UP-NETARM2410-S嵌入式实验平台的资源布局与使用方法。
4.初步掌握嵌入式Linux开发的基本过程。
二、实验内容本次实验使用Redhat Linux 9.0操作系统环境,安装ARM-Linux的开发库及编译器。
创建一个新目录,并在其中编写hello.c和Makefile文件。
学习在Linux 下的编程和编译过程,以及ARM开发板的使用和开发环境的设置。
下载已经编译好的文件到目标开发板上运行。
三、预备知识C语言的基础知识、程序调试的基础知识和方法,Linux的基本操作。
四、实验设备及工具(包括软件调试工具)硬件:UP-NETARM2410-S嵌入式实验平台、PC机Pentium 500以上, 硬盘10G以上。
软件:PC机操作系统REDHAT LINUX 9.0+MINICOM+ARM-LINUX开发环境五、实验步骤1、建立工作目录[root@zxt smile]# mkdir hello[root@zxt smile]# cd hello2、编写程序源代码在Linux下的文本编辑器有许多,常用的是vim和Xwindow界面下的gedit等,我们在开发过程中推荐使用vim,用户需要学习vim的操作方法,请参考相关书籍中的关于vim的操作指南。
Kdevelope、anjuta软件的界面与vc6.0 类似,使用它们对于熟悉windows环境下开发的用户更容易上手。
实际的hello.c源代码较简单,如下:#include <stdio.h>main(){printf(“hello world \n”);}我们可以是用下面的命令来编写hello.c的源代码,进入hello目录使用vi命令来编辑代码:[root@zxt hello]# vi hello.c按“i”或者“a”进入编辑模式,将上面的代码录入进去,完成后按Esc键进入命令状态,再用命令“:wq”保存并退出。
keil 宏条件语句Keil宏条件语句是一种用于在嵌入式系统开发中控制代码编译和执行的重要工具。
它可以根据不同的条件,在编译时决定是否包含或排除某些代码块,从而实现不同条件下的代码选择和优化。
下面是关于Keil宏条件语句的一些常见应用场景和示例:1. 根据芯片型号选择不同的驱动库:在嵌入式系统开发中,不同的芯片型号可能需要使用不同的外设驱动库。
可以使用Keil宏条件语句根据芯片型号选择不同的驱动库。
示例代码如下:```c#ifdef STM32F103#include "stm32f103_drivers.h"#elif defined(STM32F407)#include "stm32f407_drivers.h"#else#error "Unsupported chip!"#endif```2. 根据编译器版本选择不同的编译选项:不同版本的编译器可能对代码的优化和警告处理有所不同。
可以使用Keil宏条件语句根据编译器版本选择不同的编译选项。
示例代码如下:```c#if (__CC_ARM && (__ARMCC_VERSION >= 6010050))#pragma O2#pragma diag_suppress=Pa039#elif (__GNUC__ && (__GNUC__ >= 7))#pragma GCC optimize("O2")#pragma GCC diagnostic ignored "-Wmisleading-indentation"#else#error "Unsupported compiler version!"#endif```3. 根据编译器平台选择不同的标准库:不同的编译器平台可能提供不同的标准库,可以使用Keil宏条件语句根据编译器平台选择不同的标准库。
ch32中io口的宏定义ch32中IO口的宏定义定义及理由•IO口的宏定义是指在嵌入式系统中,对IO口进行可读性和可维护性的提升而定义的一系列宏。
这些宏的目的是简化IO口的操作,使代码更加清晰易懂。
•IO口是指嵌入式系统中用于输入和输出的通用引脚,常用于连接外部设备或者控制电路的状态。
通过宏定义,可以将IO口的操作封装成简单易用的函数,提高了代码的可读性和可维护性。
常见的IO口宏定义•GPIO_SET(pin):将指定IO口设置为高电平。
这个宏定义会设置指定IO口的输出寄存器对应的引脚为高电平,实现IO口输出的控制。
•GPIO_CLEAR(pin):将指定IO口设置为低电平。
这个宏定义会设置指定IO口的输出寄存器对应的引脚为低电平,实现IO口输出的控制。
•GPIO_READ(pin):读取指定IO口的电平状态。
这个宏定义会读取指定IO口的输入寄存器对应的引脚的电平状态,返回一个表示高低电平的值。
•GPIO_TOGGLE(pin):将指定IO口的电平状态翻转。
这个宏定义会根据当前IO口的电平状态来翻转它的电平,实现IO口输出状态的翻转。
•GPIO_INPUT(pin):将指定IO口设置为输入模式。
这个宏定义会设置指定IO口的控制寄存器对应的引脚为输入模式,实现IO口的输入功能。
•GPIO_OUTPUT(pin):将指定IO口设置为输出模式。
这个宏定义会设置指定IO口的控制寄存器对应的引脚为输出模式,实现IO口的输出功能。
•GPIO_PULLUP(pin):使能指定IO口的上拉电阻。
这个宏定义会设置指定IO口的上拉电阻使能位,使得IO口在断开连接时保持高电平状态。
•GPIO_PULLDOWN(pin):使能指定IO口的下拉电阻。
这个宏定义会设置指定IO口的下拉电阻使能位,使得IO口在断开连接时保持低电平状态。
书籍简介•书籍名称:《嵌入式系统开发指南》•作者:张海蓉•简介:本书是一本介绍嵌入式系统开发的指南,全面涵盖了嵌入式系统开发的基础知识、硬件设计、软件开发、实际应用等方面。
2022年职业考证-软考-嵌入式系统设计师考试全真模拟易错、难点剖析B卷(带答案)一.综合题(共15题)1.单选题采用ADSL接入Internet,用户端接入介质为(),使用的网络为()。
问题1选项A.双绞线B.红外线C.同轴电缆D.光纤问题2选项A.电话网B.电视网C.DDN专线D.5G无线广域网【答案】第1题:A第2题:A【解析】第1题:1989年在贝尔实验室诞生的ADSL是xDSL家族成员中的一员,被誉为“现代信息高速公路上的快车”。
它因其下行速率高、频带宽、性能优等特点而深受广大客户的喜爱,成为继MODEM、ISDN 之后的又一种全新更快捷,更高效的接入方式。
它是运行在原有普通电话线上的一种新的高速宽带技术。
事实上,ADSL的传输技术中,ADSL用其特有的调制解调硬件来连接现有双绞线连接的各端。
第2题: 2.单选题Kerberos系统中可通过在报文中加入()来防止重放攻击。
问题1选项A.会话密钥B.时间戳C.用户IDD.私有密钥【答案】B【解析】重放攻击(Replay Attacks)又称重播攻击、回放攻击或新鲜性攻击(Freshness Attacks),是指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。
Kerberos系统采用的是时间戳方案来防止重放攻击,这种方案中,发送的数据包是带时间戳的,服务器可以根据时间戳来判断是否为重放包,以此防止重放攻击。
3.单选题Fog computing is a mid-layer between cloud data centers and IoT devices/sensors. It provides services of(1) along with storage and networking at the proximity of the IoT devices/sensors. The fog computing concept is derived from(2) computing. Edge computing promises to bring data computation closer to the data-origin. Edge devices, in Edge computing, aren't able to support(3)applications in IoT because of their limited resources, resulting in resource-contention and increased (4). It assimilates edge devices and cloud resources to overcome (5)associated with Edge computing.问题1选项putationputerC.operating systemD.cloud system问题2选项puterB.EdgeC.EmbeddedD.server问题3选项A.simulatorB.systemC.multipleD.device问题4选项tencyB.powerC.systemer问题5选项A.memoryB.operating systemC.localD.limitations【答案】第1题:A第2题:B第3题:C第4题:A第5题:D【解析】第1题:雾计算位于云数据中心和物联网设备/传感器的中间层。
C语言中的宏定义(全面整编) 目录1. 简单宏定义2. 带参数的宏3. 运算符4. 运算符5. 宏的通用属性6. 宏定义中圆括号7. 创建较长的宏1. 较长的宏中的逗号运算符2. 宏定义中的do-while循环do3. 空操作的定义8. 预定义宏9. C语言中常用的宏1. 简单宏定义简单的宏定义有如下格式:[#define指令(简单的宏)] #define 标识符替换列表替换列表是一系列的C语言记号,包括标识符、关键字、数、字符常量、字符串字面量、运算符和标点符号。
当预处理器遇到一个宏定义时,会做一个“标识符”代表“替换列表”的记录。
在文件后面的内容中,不管标识符在任何位置出现,预处理器都会用替换列表代替它。
不要在宏定义中放置任何额外的符号,否则它们会被作为替换列表的一部分。
一种常见的错误是在宏定义中使用 = :#define N = 100 /*** WRONG ***/int a[N]; /* 会成为 int a[= 100]; */在上面的例子中,我们(错误地)把N定义成一对记号(= 和100)。
在宏定义的末尾使用分号结尾是另一个常见错误:#define N 100; /*** WRONG ***/int a[N]; /* become int a[100;]; */这里N被定义为100和;两个记号。
在一个宏定义中,编译器可以检测到绝大多数由多余符号所导致的错误。
但不幸的是,编译器会将每一处使用这个宏的地方标为错误,而不会直接找到错误的根源——宏定义本身,因为宏定义已经被预处理器删除了。
简单的宏主要用来定义那些被Kernighan和Ritchie称为“明示常量”(manifest constant)的东西。
使用宏,我们可以给数值、字符和字符串命名。
#define STE_LEN 80#define TRUE 1#define FALSE 0#define PI 3.14159#define CR '\r'#define EOS '\0'使用#define来为常量命名有许多显著的优点:1) 程序会更易读。
重点讲述avr单片机的io口操作。
很多朋友都是由51单片机走向嵌入式系统,经历了51->430 51->pic 51->avr,这样一些转换,本人粗略学了51,后直接专攻avr,为此有一些心得,和一些雕虫小技的小伎俩,希望能抛砖引玉,引发同行反思,在工作中提供举一反三后的便利。
想像51一样,在winavr中直接写上sbit KEY1 = p1^1,然后用下列语句扫描键盘吗??if(KEY1==0) keyval=1;请看下面的宏定义,其中位段的手法来源于网络,本人纯属借鉴。
之后的##,宏链接符,纯属自创,各位先行使用以下宏后,有问题直接联系本人qq21332560讨论:注明验证信息:io口//定义新的数据类型,方便进行IO端口操作。
#ifndef _bit_h#define _bit_htypedef struct //定义一个8字节的位段 bit0~7是每个位段名称 1代表一位PBIT就是整个位段的名称{unsigned bit0 : 1 ;unsigned bit1 : 1 ;unsigned bit2 : 1 ;unsigned bit3 : 1 ;unsigned bit4 : 1 ;unsigned bit5 : 1 ;unsigned bit6 : 1 ;unsigned bit7 : 1 ;}PBIT;#define PORTABIT (*(volatile PBIT *)0x3B)/*0x3B是PORTA的地址 (volatile PBIT *)0x3B 就是将这个地址强制类型装换为我们前面定义过的位段volatile关键字还不懂的话去查点资料~~前面加个*号不用我说也知道什么意思吧*/#define DDRABIT (*(volatile PBIT *)0x3A)#define PINABIT (*(volatile PBIT *)0x39)#define PORTBBIT (*(volatile PBIT *)0x38)#define DDRBBIT (*(volatile PBIT *)0x37)#define PINBBIT (*(volatile PBIT *)0x36)#define PORTCBIT (*(volatile PBIT *)0x35)#define DDRCBIT (*(volatile PBIT *)0x34)#define PINCBIT (*(volatile PBIT *)0x33)#define PORTDBIT (*(volatile PBIT *)0x32)#define DDRDBIT (*(volatile PBIT *)0x31)#define PINDBIT (*(volatile PBIT *)0x30)/*使用方法:要将PORTA的第一位输出为高电平DDRABIT.bit0=1;PORTABIT.bit0=1;或者为了便于程序的移植我们一般用宏定义#define power PORTABIT.bit0power=1;#define power_out() DDRABIT.bit0=1*///当然PORTABIT.bit0敲起来有点长可以用宏定义把他改小一点#define PORTABIT0 PORTABIT.bit0//可以改成自己看的习惯的但不要与系统头文件中定义过的冲突比如PA0 PORTA0#define PORTABIT1 PORTABIT.bit1#define PORTABIT2 PORTABIT.bit2#define PORTABIT3 PORTABIT.bit3#define PORTABIT4 PORTABIT.bit4#define PORTABIT5 PORTABIT.bit5#define PORTABIT6 PORTABIT.bit6#define PORTABIT7 PORTABIT.bit7#define PORTBBIT0 PORTBBIT.bit0#define PORTBBIT1 PORTBBIT.bit1#define PORTBBIT2 PORTBBIT.bit2#define PORTBBIT3 PORTBBIT.bit3#define PORTBBIT4 PORTBBIT.bit4#define PORTBBIT5 PORTBBIT.bit5#define PORTBBIT7 PORTBBIT.bit7#define PORTCBIT0 PORTCBIT.bit0 #define PORTCBIT1 PORTCBIT.bit1 #define PORTCBIT2 PORTCBIT.bit2 #define PORTCBIT3 PORTCBIT.bit3 #define PORTCBIT4 PORTCBIT.bit4 #define PORTCBIT5 PORTCBIT.bit5 #define PORTCBIT6 PORTCBIT.bit6 #define PORTCBIT7 PORTCBIT.bit7#define PORTDBIT0 PORTDBIT.bit0 #define PORTDBIT1 PORTDBIT.bit1 #define PORTDBIT2 PORTDBIT.bit2 #define PORTDBIT3 PORTDBIT.bit3 #define PORTDBIT4 PORTDBIT.bit4 #define PORTDBIT5 PORTDBIT.bit5 #define PORTDBIT6 PORTDBIT.bit6 #define PORTDBIT7 PORTDBIT.bit7 //**********************#define DDRABIT0 DDRABIT.bit0 #define DDRABIT1 DDRABIT.bit1 #define DDRABIT2 DDRABIT.bit2 #define DDRABIT3 DDRABIT.bit3 #define DDRABIT4 DDRABIT.bit4 #define DDRABIT5 DDRABIT.bit5 #define DDRABIT6 DDRABIT.bit6 #define DDRABIT7 DDRABIT.bit7#define DDRBBIT0 DDRBBIT.bit0 #define DDRBBIT1 DDRBBIT.bit1 #define DDRBBIT2 DDRBBIT.bit2 #define DDRBBIT3 DDRBBIT.bit3 #define DDRBBIT4 DDRBBIT.bit4 #define DDRBBIT5 DDRBBIT.bit5 #define DDRBBIT6 DDRBBIT.bit6 #define DDRBBIT7 DDRBBIT.bit7#define DDRCBIT0 DDRCBIT.bit0 #define DDRCBIT1 DDRCBIT.bit1 #define DDRCBIT2 DDRCBIT.bit2 #define DDRCBIT3 DDRCBIT.bit3 #define DDRCBIT4 DDRCBIT.bit4#define DDRCBIT6 DDRCBIT.bit6 #define DDRCBIT7 DDRCBIT.bit7#define DDRDBIT0 DDRDBIT.bit0 #define DDRDBIT1 DDRDBIT.bit1 #define DDRDBIT2 DDRDBIT.bit2 #define DDRDBIT3 DDRDBIT.bit3 #define DDRDBIT4 DDRDBIT.bit4 #define DDRDBIT5 DDRDBIT.bit5 #define DDRDBIT6 DDRDBIT.bit6 #define DDRDBIT7 DDRDBIT.bit7 //*****************#define PINABIT0 PINABIT.bit0 #define PINABIT1 PINABIT.bit1 #define PINABIT2 PINABIT.bit2 #define PINABIT3 PINABIT.bit3 #define PINABIT4 PINABIT.bit4 #define PINABIT5 PINABIT.bit5 #define PINABIT6 PINABIT.bit6 #define PINABIT7 PINABIT.bit7#define PINBBIT0 PINBBIT.bit0 #define PINBBIT1 PINBBIT.bit1 #define PINBBIT2 PINBBIT.bit2 #define PINBBIT3 PINBBIT.bit3 #define PINBBIT4 PINBBIT.bit4 #define PINBBIT5 PINBBIT.bit5 #define PINBBIT6 PINBBIT.bit6 #define PINBBIT7 PINBBIT.bit7#define PINCBIT0 PINCBIT.bit0 #define PINCBIT1 PINCBIT.bit1 #define PINCBIT2 PINCBIT.bit2 #define PINCBIT3 PINCBIT.bit3 #define PINCBIT4 PINCBIT.bit4 #define PINCBIT5 PINCBIT.bit5 #define PINCBIT6 PINCBIT.bit6 #define PINCBIT7 PINCBIT.bit7#define PINDBIT0 PINDBIT.bit0 #define PINDBIT1 PINDBIT.bit1 #define PINDBIT2 PINDBIT.bit2#define PINDBIT4 PINDBIT.bit4#define PINDBIT5 PINDBIT.bit5#define PINDBIT6 PINDBIT.bit6#define PINDBIT7 PINDBIT.bit7#endif/*--------------------------------------------------------------*/ //ICC-AVR application builder :// Target : M8// Crystal: 1.000Mhz/*--------------------------------------------------------------*//*--------------------------------------------------------------*/ //防止重复定义#ifndef __ICCAVRIO_H__#define __ICCAVRIO_H__/*--------------------------------------------------------------*/ //定义新的数据类型,方便进行IO端口操作。
2022年职业考证-软考-嵌入式系统设计师考试全真模拟易错、难点剖析AB卷(带答案)一.综合题(共15题)1.单选题以下关于各类文档撰写阶段的叙述中,不正确的是()。
问题1选项A.软件需求规格说明书在需求分析阶段撰写B.概要设计规格说明书在设计阶段撰写C.测试计划必须在测试阶段撰写D.测试分析报告在测试阶段撰写【答案】C【解析】测试过程基本上与开发过程平行进行,在需求分析阶段,就需要对测试计划进行撰写。
C选项描述错误,其他选项的说法是正确的。
2.单选题关于中间件软件,下列叙述错误的是()。
问题1选项A.中间件是一种独立的系统软件或服务程序B.中间件一般运行于多种硬件和操作系统平台C.分布式系统中,应用软件借助中间件软件在不同的技术平台之间共享资源D.中间件软件可以屏蔽平台操作系统差异,但不能屏蔽网络协议差异【答案】D【解析】在操作系统内核、设备驱动程序和应用软件之外的所有系统软件,把原本属于应用软件层的一些通用的功能模块抽取出来,形成独立的一层软件,从而为运行在它上面的那些应用软件提供一个灵活、安全、移植性好、相互通信、协同工作的平台。
除了操作系统,中间件还能够屏蔽网络协议的差异,为应用程序提供多种通讯机制。
3.单选题下列属于CPU中算术逻辑单元的部件是()。
问题1选项A.程序计数器B.加法器C.指令寄存器D.指令译码器【答案】B【解析】算术逻辑单元是运算器的重要组成部件,负责处理数据,实现对数据的算术运算和逻辑运算。
所以本题正确的选项是BCPU中其他部件作用:程序计数器是用于存放下一条指令所在单元的地址的地方。
在程序执行前,必须将程序的起始地址,即程序的一条指令所在的内存单元地址送入程序计数器,当执行指令时,CPU将自动修改程序计数器的内容,即每执行一条指令程序计数器增加一个量,使其指向下一个待指向的指令。
程序的转移等操作也是通过该寄存器来实现的。
累加器是专门存放算术或逻辑运算的一个操作数和运算结果的寄存器。
写好C语言,漂亮的宏定义很重要
2009-12-09 17:08
写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等。
下面列举一些成熟软件中常用得宏定义。
1,防止一个头文件被重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif
2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。
typedef unsigned char boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
//下面的不建议使用
typedef unsigned char byte; /* Unsigned 8 bit value type. */ typedef unsigned short word; /* Unsinged 16 bit value type. */ typedef unsigned long dword; /* Unsigned 32 bit value type. */ typedef unsigned char uint1; /* Unsigned 8 bit value type. */ typedef unsigned short uint2; /* Unsigned 16 bit value type. */
typedef unsigned long uint4; /* Unsigned 32 bit value type. */ typedef signed char int1; /* Signed 8 bit value type. */ typedef signed short int2; /* Signed 16 bit value type. */ typedef long int int4; /* Signed 32 bit value type. */ typedef signed long sint31; /* Signed 32 bit value */ typedef signed short sint15; /* Signed 16 bit value */ typedef signed char sint7; /* Signed 8 bit value */
3,得到指定地址上的一个字节或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
4,求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
5,得到一个field在结构体(struct)中的偏移量
#define FPOS( type, field ) \
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
6,得到一个结构体中field所占用的字节数
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
7,按照LSB格式把两个字节转化为一个Word
#define FLIPW( ray ) ( (((word) (ray)[0]) << 8) + (ray)[1] )
8,按照LSB格式把一个Word转化为两个字节
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
9,得到一个变量的地址(word宽度)
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
10,得到一个字的高位和低位字节
#define WORD_LO(***) ((byte) ((word)(***) & 255))
#define WORD_HI(***) ((byte) ((word)(***) >> 8))
11,返回一个比X大的最接近的8的倍数
#define RND8( x ) ((((x) + 7) / 8 ) * 8 )
12,将一个字母转换为大写
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
13,判断字符是不是10进值的数字
#define DECCHK( c ) ((c) >= '0' && (c) <= '9')
14,判断字符是不是16进值的数字
#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\
((c) >= 'A' && (c) <= 'F') ||\
((c) >= 'a' && (c) <= 'f') )
15,防止溢出的一个方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
16,返回数组元素的个数
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
17,返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n) #define MOD_BY_POWER_OF_TWO( val, mod_by ) \
( (dword)(val) & (dword)((mod_by)-1) )
18,对于IO空间映射在存储空间的结构,输入输出处理
#define inp(port) (*((volatile byte *) (port)))
#define inpw(port) (*((volatile word *) (port)))
#define inpdw(port) (*((volatile dword *)(port)))
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
19,使用一些宏跟踪调试
A N S I标准说明了五个预定义的宏名。
它们是:
_ L I N E _
_ F I L E _
_ D A T E _
_ T I M E _
_ S T D C _
如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。
记住编译程序
也许还提供其它预定义的宏名。
_ L I N E _及_ F I L E _宏指令在有关# l i n e的部分中已讨论,这里讨论其余的宏名。
_ D AT E _宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
源代码翻译到目标代码的时间作为串包含在_ T I M E _中。
串形式为时:分:秒。
如果实现是标准的,则宏_ S T D C _含有十进制常量1。
如果它含有任何其它数,则实现是
非标准的。
可以定义宏,例如:
当定义了_DEBUG,输出数据信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date)
printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_) #else
#define DEBUGMSG(msg,date)
#endif
20,宏定义防止使用是错误
用小括号包含。
例如:#define ADD(a,b) (a+b)
用do{}while(0)语句包含多语句防止错误
例如:#difne DO(a,b) a+b;\
a++;
应用时:if(….)
DO(a,b); //产生错误
else。