在一个C源程序中,除了变量和函数的定义、声明以及表达式等基本程序语句外,还包括一些#号开始的编译预处理命令(Preprocessor Directive)。这些预处理命令由编译器正式编译之前调用相应的预编译函数来解释和执行。主要的编译预处理功能有宏定义、文件包含、条件编译及pragma命令等。
1.宏定义、文件包含与条件编译
(1)宏定义
宏(Macro)定义是指用一个指定的名字来代表一个常量表达式或字符串,其复杂性形式是带参数的宏。宏定义的一般格式为
#define标识符 常量表达式或字符串
例如
#define PI 3.14159 //定义一个符号常量PI代表常数3.14159
#define Uint16 unsigned int //定义一个类型符号Uint16代表无符号整型
#define EINT asm("clrcINTM") //定义一个符号EINT代表一条开中断汇编指令
通常#define出现在源程序的首部,使用宏名之前一定要用#define进行宏定义。宏定义不是C语句,不必在行末尾加分号。也可以将常用的宏定义放到头文件中。
(2)文件包含
文件包含是指一个程序文件将另一个指定文件的内容全部包含进来。一般格式为
#include “被包含文件名” 或 #include <被包含文件名>
其中“被包含文件名”是一个已经存在于系统中的文件名字。被包含文件通常称为头文件,通常.h以作为后缀,例如
#include <math.h>
其功能是将头文件“math.h”的内容嵌入到该命令行处,使它成为源程序的一部分。当用一对尖括号时,编译系统按设定的标准目录搜索头文件。当用一对双引号时,编译系统先在源文件所在的目录中搜索,搜索不到,再按设定的标准目录搜索头文件。
文件包含预处理命令行通常放在文件的开头,被包含的文件内容通常是一些公用的宏定义如外设寄存器定义或外部变量说明等。例如
#include<DSP2803x_Device.h>
该头文件包了IER、IFR寄存器定义、CPU控制、类型定义及片内外设寄存器定义等。该头文件的部分内容为
extern cregister volatile unsigned int IFR; //用cregister声明中断标志寄存器IFR
extern cregister volatile unsigned int IER; //用cregister声明中断使能寄存器IER
#define EINT asm("clrcINTM") //定义宏EINT,代表使能中断汇编指令clrcINTM
#define DINT asm("setcINTM") //定义宏DINT,代表使能禁止汇编指令setcINTM
#defineEALLOWasm("EALLOW) //解除EALLOW保护,代表汇编指令EALLOW
#define EDIS asm("setcINTM") //添加EALLOW保护,代表汇编指令EDIS
typedef int int 16 //定义类型名int16,代表类型int
typedef long int32
typedef unsigned int Uint16
typedef unsigned long Uint32
使用包含文件应注意以下几点:
1)调用标准库函数例如数学函数时,一定要包含所要用到的库文件。
2)头文件只能是ASCII文件,不能是目标代码文件。
3)一个#include命令只能包含一个头文件。如要包含多个头文件,则须用多个#include命令。
4)文件包含可以嵌套,即被包含的文件可以再包含另外的头文件。
(3)条件编译
条件编译是指在编译C文件之前,根据条件决定编译的范围。其格式有
1)条件编译格式1:
#ifdef 标识符
程序段1
#else
程序段2
#endif
其功能是若标识符已被定义过,则对程序段1进行编译;否则对程序段2进行编译。可以简化为
#ifdef标识符
程序段1
#endif
值得说明的是,只要条件编译之前有命令行“#define标识符”就可以了,无论该宏的值是什么都无关紧要。
2)条件编译格式2:
#ifndef 标识符(www.daowen.com)
程序段1
#else
程序段2
#endif
其功能是若标识符未被定义过,则对程序段1进行编译;否则对程序段2进行编译。例如
#ifndef DSP28_DATA_TYPES
#define DSP28_DATA_TYPES
typedef int int16
typedef long int32
…
#endif
2.pragma命令
pragma是一类编译预处理命令,通知编译预处理器如何处理函数。C28x C/C++支持如下5个pragma预处理命令:CODE_SECTION、DATA_SECTION、INTERRUPT、FUNC_EXT_CALLED和FAST_CALL。
(1)CODE_SECTION
该命令的C语法格式为
#pragma CODE_SECTION(func,"section name")
它为函数func在一个名为section name的段(section)中指定空间。将一个代码对象链接到一个不同于程序段.text的空间时,该命令非常有用。例如,
char bufferA[80];
#pragma CODE_SECTION(funA,“codeA”)
char funA(inti);
void main()
{
char c;
c=funA(1);
}
char fun A(inti)
{
return bufferA[i];
}
(2)DATA_SECTION
该命令的C语法格式为
#pragma DATA_SECTION(symbol,"section name")
它为符号symbol在一个名为section name的数据段中指定空间。将一个数据对象链接到一个不同于.bss段的空间时,该命令非常有用。例如
#pragma DATA_SECTION(bufferB,"my_sect")
char bufferB[512]; //字符数组bufferB
数据块bufferB被定位于my_sect段中,my_sect段在命令文件(.cmd)中规定了物理地址。
(3)INTERRUPT
该命令的C语法格式为
#pragma INTERRUPT(func)
参数func为C函数名。该命令允许用户直接采用C/C++代码处理中断。
(4)FUNC_EXT_CALLED
该命令的C语法格式为
#pragma FUNC_EXT_CALLED(func)
参数func为C函数名。编译器有一个优化器,该优化器有一种优化方法,即将从未在main()函数中被直接或间接调用过的函数去掉。若采用C与汇编混合编程,某函数可能在汇编语言中被调用,此时为了防止优化器将这些函数去掉,可以在C程序中采用该命令告诉编译器保留该函数。
(5)FAST_CALL
该命令的C语法格式为
#pragma FAST_CALL(func)
该命令允许在C/C++中直接调用汇编语言编写的函数func。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。