编译预处理语句,通过预处理命令可扩展C语言程序设计的条件

澳门永利网上娱乐 1

 

编写翻译预处理语句

在嵌入式系统一编写程中,不管是根本的驱动程序依旧应用程序的编辑,都关涉到大气的预处理与规则编写翻译,这样做的裨益首要映未来代码的移植性强以及代码的改动方便等特色,因而引进了预处理与标准编写翻译的定义。在C语言的主次中可归纳各类以符号#开头的编写翻译指令,这么些指令称为预处理命令。预处理命令属于C语言编写翻译器,而不是C语言的组成都部队分。通过预处理命令可扩张C语言程序设计的条件。

编写翻译预处理是VerilogHDL编译系统的3个组成都部队分,指编写翻译系统会对1部分尤其命令举办预处理,然后将预处理结果和源程序壹起在进行普通的编写翻译处理。以”`”
(反引号)开端的1些标识符是编写翻译预处理语句。在Verilog
HDL语言编写翻译时,特定的编写翻译指令在全数编写翻译进度中有效(编写翻译进程可超越多少个公文),直到遇见任何不相同的编写翻译程序指令。常用的编写翻译预处理语句如下:

 

(1)`define,`undef

 

(2)`include

注:该种类内容整理自以下链接。

(3)`timescale

http://blog.csdn.net/dlutbrucezhang/article/details/8753765

(4)`ifdef,`else.`endif

 

(5)`default_nettype;

预处理的做事章程

(6)`resetall

 

(7)`unconnect_drive,`nounconnected-drive;

一.一 预处理的机能

(8)`celldefine,`endcelldefine

在合龙开发条件中,编写翻译,链接是还要达成的。其实,C语言编写翻译器在对源代码编写翻译此前,还须求越发的处理:预编写翻译。预编译的首要性作用如下:


  • 将源文件中以”include”格式蕴含的公文复制到编写翻译的源文件中。
  • 用实际值替换用“#define”定义的字符串。
  • 根据“#if”后边的尺度决定须求编写翻译的代码。

宏定义

一.二 预处理的工作方法
 
预处理的行事是由指令控制的。那些指令是由#字符伊始的某个下令。
#define指令定义了3个宏,用来表示任李新发西的二个限令,经常是某1个品种的常量。预处理会通过将宏的名字和它的概念存款和储蓄在协同来响应#define指令。当以此宏在前面包车型大巴顺序中运用到时,预处理器”扩大”了宏,将宏替换为它所定义的值。
#include指令告诉预处理器打开三个一定的文书,将它的内容作为正在编写翻译的文本的1有的“包罗”进来。例如:上边那行命令:
  #include<stdio.h>

`define指令是贰个宏定义命令,通过二个点名的标识符来代表一个字符串,能够追加Veirlog
HDL代码的可读性和可维护性,找出参数或函数不正确或不允许的地方。

指令预处理器打开3个名叫stdio.h的文本,并将它的始末加到当前的主次中。

`define指令类似C语言中的#define指令,能够在模块的个中或外部定义,编写翻译器在编写翻译进度中境遇该语句将把宏文本替换为宏的名字。`define的评释语法格式如下:
`define,<macro_name><Text>

预处理器的输入是1个C语言程序,程序恐怕含有指令。预处理器会执行那么些指令,并在处理过程中剔除那些指令。预处理器的输出是此外三个顺序:原程序的二个编写制定后的本子,不再包罗指令。预处理器的输出被直接提交编写翻译器,编写翻译器检查程序是还是不是有不当,并经程序翻译为对象代码。
 

对于已扬言的说话,在代码中的应用格式如下(不要漏掉宏前面包车型大巴”`”):

 

`macro-name

预处理指令

例如:define  MAX-BUS-SIZE  32

 2.1.预拍卖指令

绝半数以上预处理器指令属于上面三种档次:

Reg[`MAX-BUS-SIZE-1:0]AddReg;

  • 宏定义:#define
    指令定义贰个宏,#undef指令删除二个宏定义。
  • 文本包蕴:#include指令导致一个钦命文件的始末被含有到程序中。
  • 规范编写翻译:#if,#ifdef,#ifndef,#elif,#else和#endif指令能够根据编写翻译器能够测试的准绳来将一段文本包罗到程序中或解决在程序之外。

一旦`define指令被编写翻译,其在整个编写翻译进度中都有效。例如,通过另1个文本中的`define指令,MAX-BUS-SIZE能被八个公文使用。

剩下的#error,#line和#pragma指令更出奇的指令,较少用到。

`undef指令用于撤销前面定义的宏。例如:

二.二.限令规则
 
指令都以以#开始。#标记不需求在一行的行首,只要他后边有空白字符就行。在#后是指令名,接着是指令所需求的其他音信。在指令的标志之间能够插入任意数量的空格或横向制表符。指令总是第几个换行符处截止,除非显明地指明要再而三。
命令能够现身在先后中的任哪个地方方。我们平日将#define和#include指令放在文件的开首,其余指令则位居前边,甚至在函数定义的中等。
注脚能够与指令放在同一行。

`undef  WORD16

 

宏定义命令#define

Wire [`WORD:1]Bus;

使用#define命令并不是确实的定义符号常量,而是定义一个得以替换的宏。被定义为宏的标志符称为“宏名”。在编写翻译预处理进度时,对程序中具有出现的“宏名”,都用宏定义中的字符串去代换,这叫做“宏代换”或“宏展开”。

 

`undef  WORD

在C语言中,宏分为有参数和无参数二种。

宏定义指令的注意事项:

3.一.无参数的宏

(1)    宏定义的称谓能够是大写,也足以是小写,但要注意不要和变量名重复。

其定义格式如下:
  #define 宏名  字符串

(2)    和全数编写翻译器伪指令壹样,宏定义在超越单个文件边界时仍有效(对工程的别的源文件),除非被前边的`define、`undef或`resetall伪指令覆盖,不然`define不收范围限制。

在以上宏定义语句中,各部分的意义如下:

(三)    当用变量定义宏时,变量能够在宏正文中使用,并且在使用宏的时候能够用实际的变量表明式代替。

#:表示那是一条预处理命令(凡是以“#”开端的均为预处理命令)。

(4)    通过用反斜杠”\”转义中间换行符,宏定义能够当先几行,新的行是宏正文的1有些。

define:关键字“define”为宏定义命令。

(5)    宏定义行末不要求加上分号表示停止。

宏名:是二个标示符,必须符合C语言标示符的明确,1般以大写字母标示宏名。

(陆)    宏正文无法分开的言语符号包蕴注释、数字、字符串、保留的主要性字、运算符。

字符串:可以是常数,表达式,格式串等。在前方使用的标志常量的概念就是八个无参数宏定义。

(7)    编译器伪指令不允许作为宏的名字。

留神:预处理命令语句前边壹般不会助长分号,借使在#define最终有分公司,在宏替换时分号也将替换成源代码中去。在宏名和字符串之间能够有私行个空格。

(八)    宏定义中的文本也能够是二个表明式,并不只用于变量名称的更迭。

例如:


  #define PI 3.14

define和parameter

在应用宏定义时,还索要小心以下几点:

`define和parameter是有分其他。`define和parameter都得以用于完结文本替换,但其设有本质上的两样,前者是编写翻译在此以前就预处理,而后人是在正规编写翻译进程中实现替换的。其它,`define和parameter存在下列两点分化之处:
   
(一)效率域不一致。Parameter成效于声明的拾贰分文件;`define从编写翻译器读到那条指令开首到编写翻译甘休都有效,除非蒙受`undef命令使之失效,能够使用于整个工程。假若要让parameter效能于一体项目,能够将宣示语句写于独立文件中,并用)`include让各种文件都带有申明文件。

宏定义是宏名来表示3个字符串,在宏展开时又以该字符串取代宏名。这只是1种简易的更换,字符串中能够含别的字符,能够是常数,也可以是表明式,预处理程序对它不作任何检查。如有错误,只幸好编写翻译已被宏展开后的源程序时发现。

`define可以写在代码的此外岗位,而Parameter则必须在行使在此以前定义。平日编写翻译器都足以定义编写翻译顺序,或然从最底部模块开始编写翻译,因而写在最尾部就足以了。
   
(二)传递作用各异。Parameter能够看成模块例化时的参数字传送递,完毕参数化调用;`define语句则尚未此成效。`define语句能够定义表达式,而Parameter只好定义变量。

宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。

澳门永利网上娱乐 2

宏名在源程序只可以够若用引号括起来,则预处理程序不对其作宏替换。


宏定义允许嵌套,在宏定义的字符串中得以选择已经定义的宏名。在宏展开时由预处理程序层层替换。

 版权全数权归卿萃科技(science and technology) 杭州FPGA事业部,转发请评释出处
 

习惯上宏名可用大写字母表示,以便于与变量分歧。但也允许用小写字母。

 作者:杭州卿萃科技(science and technology)ALIFPGA 

三.二带参数的宏

 最初的文章地址:底特律卿萃科技(science and technology)FPGA极客空间
微信公众号

#define命令定义宏时,仍是可以够为宏设置参数。与函数中的参数近似,在宏定于中的参数为格局参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,还要用实参去代换形参。


带参宏定义的形似格局为:
  #define 宏名(形参表)  字符串

  

在概念带参数的宏时,宏名和形参表之间不可能有空格出现,不然,就将宏定义成为无参数情势,而致使程序出错。

 
  澳门永利网上娱乐 3

例如:

**

  #define ABS(x) (x)<0?-(x):(x)

**

如上的宏定义中,假如x的值小于0,则运用①元运算符(-)对其取负,获得正数。


带参的宏和带参的函数相似,但其本质是差异的。使用带参宏时,在预处理时将程序源代码替换成相应的岗位,编写翻译时收获完全的靶子代码,而不开始展览函数调用,由此程序执行功效要高些。而函数调用只需求编写翻译2次函数,代码量较少,①般景况下,对于简易的功用,可应用宏替换的花样来选拔。

 

三.三.预处理操作符#和##

3.3.1.操作符#

在使用#define定义宏时,可利用操作符#在字符串中输出实参。

例如:

  #define AREA(x,y)
printf(“长为“#x”,宽为“#y”的圆锥形的面积:%d\n”,(x)*(y));

3.3.2.操作符##

与操作符#类似,操作符##也可用在带参宏中替换部分内容。该操作符将宏中的五个部分连接成3个剧情。例如,定义如下宏:
#define VAR(n)   v##n

当使用一下主意引用宏:
VAR(1)

预处理时,将获取以下情势:
V1

如若使用以下宏定义:
#define FUNC(n)  oper##n

当实参为壹时,预处理后获取一下情势:
oper1

文本蕴含include

当3个C语言程序由五个文件模块组成时,主模块中貌似包括main函数和一部分当下程序专用的函数。程序从main函数初阶进行,在实践进度中,可调用当前文件中的函数,也可调用其他文件模块中的函数。

假如在模块中要调用其余文件模块中的函数,首先必须在主模块中宣示该函数原型。一般都以利用文件包涵的方法,包罗别的文件模块的头文件。
文件包罗中钦赐的文书名即能够用引号括起来,也足以用尖括号括起来,格式如下:
#include< 文件名>


#include“文件名”
一旦使用尖括号<>括起文件名,则编写翻译程序将到C语言开发条件中设置好的
include文件中去找内定的文书。

因为C语言的标准头文件都存放在include文件夹中,所以1般对标准头文件选择尖括号;对编制程序本身编辑的公文,则使用双引号。要是协调编写的文件不是存放在在当前工作文件夹,能够在#include命令前边加在路径。

#include命令的法力是把钦定的文本模块内容插入到#include所在的地方,当程序编写翻译链接时,系统会把具备#include钦赐的文件链接生成可实行代码。文件包括必须以#起来,表示那是编写翻译预处理命令,行尾不能够用分号截至。

#include所包蕴的文件,其扩充名能够是“.c”,表示包蕴普通C语言源程序。也足以是
“.h”,表示C语言程序的头文件。C语言系统中山高校量的概念与评释是以头文件情势提供的。
通过#define包括进来的文件模块中还足以再包蕴其余文件,那种用法称为嵌套包括。嵌套的层数与具体C语言系统有关,然而壹般能够嵌套八层以上。

规则编写翻译

预处理器还提供了标准化编写翻译功效。在预处理时,遵照分裂的尺码去编写翻译程序的不等部分,从而赢得分歧的对象代码。使用条件编写翻译,可惠及地处理程序的调节版本和专业版本,也可应用口径编写翻译使程序的移植更利于。

5.1使用#if
与C语言的规范分支语句看似,在预处理时,也得以应用分支,根据不相同的境况编写翻译分歧的源代码段。

#if 的施用格式如下:
#if 常量表明式
   程序段
#else

*  程序段 #endif*

该标准编写翻译命令的执行进度为:若常量表达式的值为真(非0),则对程序段一开始展览编写翻译,否则对程序段二展开编写翻译。因而能够使程序在分化尺度下做到不一致的效用。
例如:

#define DEBUG 1

int main()
{
   int i,j;
   char ch[26];

   for(i='a';j=0;i<='z';i++,j++)
   {
       ch[j]=i;
       #if DEBUG
          printf("ch[%d]=%c\n",j,ch[j]);
       #endif
   }

   for(j=0;j<26;j++)
   {
       printf("%c",ch[j]);
   }

   return 0;
}

#if预编译命令还可选取多分支语句格式,具体格式如下:
#if 常量表达式 1

*    程序段 1*

#elif 常量表明式 2

*    程序段 2*

… …

#elif 常量表明式 n

*    程序段 n*

#else

*    程序段 m*

#endif

关键字#elif与多分支if语句中的else if类似。
例如:

#define os win

#if os=win
    #include"win.h"
#elif os=linux
    #include"linux.h"
#elif os=mac
    #include"mac.h"
#endif

#if和#elif还足以拓展嵌套,C8玖标准中,嵌套深度能够到达8层,而C9九允许嵌套达到六三层。在嵌套时,各种#endif,#else或#elif与近期的#if或#elif配对。
例如:

#define MAX 100
#define OLD -1

int main()
{
int i;
#if MAX>50
{  
    #if OLD>3
    {
        i=1;
    {
    #elif OLD>0
    {
        i=2;
    }
    #else
    {
        i=3;
    }
    #endif
}
#else
{
    #if OLD>3
    {
        i=4;
    }
    #elif OLD>4
    {
        i=5;
    }
    #else
    {
        i=6;
    }
    #endif
}
#endif

return 0;
}

5.2使用#ifdef和#ifndef

在上头的#if条件编写翻译命令中,需求判定符号常量定义的具体值。在多如牛毛场合下,其实不供给判定符号常量的值,只须要看清是还是不是定义了该符号常量。那时,可不利用#if命令,而采纳别的3个预编写翻译命令———#ifdef.

#ifdef命令的运用格式如下:
#ifdef 标识符
程序段 1

#else

*    程序段 2*

#endif

其意义是,若是#ifdef前边的标识符已被定义过,则对“程序段1”进行编写翻译;假诺未有概念标识符,则编写翻译“程序段二”。一般不选用#else及末端的“程序二”。

而#ifndef的意思与#ifdef相反,其格式如下:
#ifndef 标识符
澳门永利网上娱乐,    程序段 1

#else

*    程序段 2*

#endif

其含义是:即便未定义标识符,则编写翻译“程序段1”;否则编写翻译“程序段2”。

5.3使用#defined和#undef

与#ifdef类似的,可以在#if命令中应用define来判断是或不是已定义钦定的标识符。例如:
#if defined 标识符
程序段 1  

#endif

与下部的标志情势意义一样。
#ifdef 标识符
    程序段 1

#endif

也可应用逻辑运算符,对defined取反。例如:
#if ! define 标识符
    程序段 1

#endif

与下部的标示格局意义壹样。
#ifndef 标识符
    程序段 1

#endif

在#ifdef和#ifndef命令后边的标识符是行使#define实行定义的。在程序中,还能动用#undef撤废对标识符的定义,其款式为:
#undef 标识符
例如:

#define MAX 100
……
#undef MAX

在以上代码中,首先选拔#define定义标识符MAX,经过壹段程序代码后,又可以动用#undef裁撤已定义的标识符。使用#undef命令后,再使用#ifdef
max,将不会编写翻译后的源代码,因为此时标识符MAX已经被撤回定义了。

任何预处理命令

 陆.一.预订义的宏名

ANSI
C标准预约义了几个宏名,每一种宏名的内外均有多少个下画线,避免与程序员定义相同的宏名(一般都不会定义前后有多个下划线的宏)。那多个宏名如下:

  •  __DATE__:当前源程序的开创日期。
  •  __FILE__:当前源程序的文件名称(包涵盘符和途径)。
  •  __LINE__:当前被编写翻译代码的行号。
  •  __STDC__:再次来到编写翻译器是或不是位标准C,若其值为壹意味着符合标准C,不然不是正规C.
  •  __TIME__:当前源程序的创造时间。

例如:

#include<stdio.h>

int main()
{
   int j;
   printf("日期:%s\n",__DATE__);
   printf("时间:%s\n",__TIME__};
   printf("文件名:%s\n",__FILE__);
   printf("这是第%d行代码\n",__LINE__);
   printf("本编译器%s标准C\n",(__STD__)?"符合":"不符合");
   return 0;
}

 

6.2.重置行号和文件名命令#line

使用__LINE__预定义宏名正在编写翻译的先后行号。使用#line命令可改变预约义宏__LINE__与__FILE__的始末,该命令的基本形如下:
 #line number[“filename”]

中间的数字为3个正整数,可选的文件名称叫使得文件标识符。行号为源代码中当前行号,文件名称叫源文件的名字。命令为#line主要用来调节和测试以及其余出色应用。
例如:

#include<stdio.h>
#include<stdlib.h>

#line 1000
int main()
{
    printf("当前行号:%d\n",__LINE__);
    return 0;
}

 

在上述程序中,在第伍行中选拔#line定义的行号为从一千方始(不包含#line那行)。所以第6行的号子将为1000,第陆作为100一,第10作为拾02,第柒行事十0叁.

6.3.修改编写翻译器设置命令#pragma

#pragma命令的效应是设定编写翻译器的意况,只怕提示编写翻译器完全壹些特定的动作。#pragma命令对种种编写翻译器给出了二个方法,在保持与C语言完全协作的图景下,给出主机恐怕操作系统专有的特征。其格式1般为:
#pragma Para

里头,Para为参数,可选拔的参数很多,下边列出常用的参数:
Message参数,该参数能够在编写翻译消息输出窗口中输出对应的音讯,那对于源代码音讯的支配是格外主要的,其使用办法是:
#pragma message(音信文本)

当编写翻译器碰到那条指令时,就在编写翻译输出窗口元帅音讯文本展现出来。
此外一个行使相比多得pragma参数是code_seg.格式如:
#pragma code_seg([“section_name”[,section_class]])

它亦可设置程序中函数代码存放的代码段,在开发驱动程序的时候就会选取到它。
参数once,可保障头文件被编译3回,其格式为:
#pragma once

如若在头文件的最开始出席这条指令就可见确认保证头文件被编写翻译1回。

6.四.发生错误消息命令#error

#error命令强制编写翻译器截止编写翻译,并出口叁个错误新闻,主要用于程序调节和测试。其行使如下:
#error 新闻错误
留神,错误消息不用双括号括起来。当遇到#error命令时,错误音讯将显示出来。
例如,以下编写翻译预处理器命令判断预定义宏__STDC__,假诺其值不为一,则显得叁个错误音信,提醒程序员该编写翻译器不协理ANSI
C标准。

#if __STDC__!=1
   #error NOT ANSI C
#endif

 

内联函数

在使用#define定义带参数宏时,在调用函数时,一般供给充实系统的支出,如参数字传送递,跳转控制,再次来到结果等额外操作供给系统内部存款和储蓄器和实施时间。而选择带参数宏时,通过宏替换可再编写翻译前将函数代码展开导源代码中,使编写翻译后的靶子文件含有多段重复的代码。那样做,会追加程序的代码量,都得以裁减执行时间。
在C9玖标准钟,还提供其余壹种缓解方法:使用内联函数。
在程序编写翻译时,编写翻译器将顺序中冒出的内联函数的调用表明式用内联函数的函数体来展开替代。鲜明,那种做法不会时有发生转去转回得难点。都以由于在编译时将函数体中的代码被取而代之到程序中,因而会大增指标代码量,进而扩展空间的支付,而在时刻支出上不像函数调用时那么大,可知它是以追加目的代码为代码来换取时间的节约。
概念内联函数的主意很不难,只要在定义函数头的先头加上关键字inline即可。内联函数的定义与一般函数一样。例如,定于一个七个整数相加的函数:

#include<stdio.h>
#include<stdlib.h>

inline int add(int x,int y);

inline int add(int x,int y)
{
   return x+y;
}

int main()
{
   int i,j,k;
   printf("请输入两个整数的值:\n");
   scanf("%d %d",&i,&j);
   k=add(i,j);
   printf("k=%d\n",k);

   return 0;
}

 

在程序中,调用函数add时,该函数在编写翻译时会将上述代码复制过来,而不是像相似函数那样是运营时被调用。

内联函数有所相似函数的特点,它与一般函数所不相同之处在于函数调用的处理。1般函数进行调用时,要讲程序执行权转导被调函数中,然后再回到到调用到它的函数中;而内联函数在调用时,是将调用表明式用内联函数体来替换。在应用内联函数时,应该专注如下几点:

  • 在内联函数内部允许用循环语句和开关语句。
  • 内联函数的定义必须出现在内联函数率先次被调用以前。

骨子里,在程序中声称二个函数为内联时,编写翻译未来这么些函数不肯定是内联的,即程序只是提议编写翻译器使用内联函数,可是编译器会依据函数意况决定是不是采取内联,所以只要编写的内联函数中冒出循环只怕开关语句,程序也不会唤醒出错,但相当函数已经不是内联函数了。1般都以讲贰个袖珍函数作为内联函数。