嵌入式C语言常用的5类预处理
yuyutoo 2024-12-14 15:53 4 浏览 0 评论
在嵌入式系统编程中不管是内核的驱动程序还是应用程序的编写,涉及到大量的预处理与条件编译,这样做的好处主要体现在代码的移植性强以及代码的修改方便等方面。因此引入了预处理与条件编译的概念。在C语言的程序中可包括各种以符号#开头的编译指令,这些指令称为预处理命令。预处理命令属于C语言编译器,而不是C语言的组成部分。通过预处理命令可扩展C语言程序设计的环境。预处理的行为是由指令控制的。这些指令是由#字符开头的一些命令。
一、预处理指令
大多数预处理器指令属于下面3种类型:
●宏定义:#define 指令定义一个宏,#undef指令删除一个宏定义。
●文件包含:#include指令导致一个指定文件的内容被包含到程序中。
●条件编译:#if,#ifdef,#ifndef,#elif,#else和#endif指令可以根据编译器可以测试的条件来将一段文 本包含到程序中或排除在程序之外。
剩下的#error,#line和#pragma指令更特殊的指令,较少用到。
二、宏定义
1、无参宏
#define 宏名 字符串
●宏名在源程序只能够若用引号括起来,则预处理程序不对其作宏替换。
●宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序 层层替换。
●习惯上宏名可用大写字母表示,以方便与变量区别。但也允许用小写字母。
2、带参数的宏
#define 宏名(形参表) 字符串
在定义带参数的宏时,宏名和形参表之间不能有空格出现,否则,就将宏定义成为无参数形 式, 而导致程序出错。
Eg:#define ABS(x) (x)<0?-(x):(x) 这个宏定义中,如果x的值小于0,则使用一元运算符(-)对其 取负,得到正数。
3、预处理操作符#和##
在使用#define定义宏时,可使用操作符#在字符串中输出实参。Eg:
#define AREA(x,y) printf(“长为“#x”,宽为“#y”的长方形的面积:%d\n”,(x)*(y));
##与操作符#类似,操作符##也可用在带参宏中替换部分内容。该操作符将宏中的两个部分连 接成一个内容。例如,定义如下宏:
#define VAR(n) v##n
当使用一下方式引用宏:
VAR(1)
三、文件包含
#include< 文件名>
#include“文件名”
其扩展名可以是“.c”,表示包含普通C语言源程序。也可以是 “.h”,表示C语言程序的头文件。C语言 系统中大量的定义与声明是以头文件形式提供的。
用<>括起文件名,一般指系统头文件,编译程序将到C语言开发环境中设置好的 include文件中去 找指定的文件。
用""括起文件名则是自定义头文件
四、条件编译
1、单条件判断
#if
程序段
#else
程序段
#endif
该条件编译命令的执行过程为:若常量表达式的值为真(非0),则对程序段1进行编译,否则对程序 段2进行编译。因此可以使程序在不同条件下完成不同的功能。
2、多条件判断
#if 常量表达式 1
程序段 1
#elif 常量表达式 2
程序段 2
… …
#elif 常量表达式 n
程序段 n
#else
程序段 m
#endif
3、使用#ifdef和#ifndef
判断符号常量定义
#ifdef命令的使用格式如下:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
4、使用#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 标识符
Eg:
#define MAX 100
#undef MAX
五.其他预处理命令
1、预定义的宏名
ANSI C标准预定义了五个宏名,每个宏名的前后均有两个下画线,避免与程序员定义相同的宏名 (一般都不会定义前后有两个下划线的宏)。这5个宏名如下:
●__DATE__:当前源程序的创建日期。
● __FILE__:当前源程序的文件名称(包括盘符和路径)。
● __LINE__:当前被编译代码的行号。
● __STDC__:返回编译器是否位标准C,若其值为1表示符合标准C,否则不是标准C.
● __TIME__:当前源程序的创建时间。
Eg:
#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;
}
2、行号和文件名命令#line
使用__LINE__预定义宏名编译的程序行号。使用#line命令可改变预定义宏__LINE__与__FILE__的内容,该命令的基本形如下:
#line number[“filename”]
其中的数字为一个正整数,可选的文件名为有效文件标识符。行号为源代码中当前行号,文件名为源文件的名字。命令为#line主要用于调试以及其他特殊应用。
Eg:
1:#include<stdio.h>
2:#include<stdlib.h>
4:#line 1000
6:int main()
7:{
8: printf("当前行号:%d\n",__LINE__);
9: return 0;
10:}
3、修改编译器设置命令 #pragma
#pragma命令的作用是设定编译器的状态,或者指示编译器完全一些特定的动作。#pragma命令对每个编译器给出了一个方法,在保持与C语言完全兼容的情况下,给出主机或者操作系统专有的特征。其格式一般为:
#pragma Para
其中,Para为参数,可使用的参数很多,下面列出常用的参数:
Message参数,该参数能够在编译信息输出窗口中输出对应的信息,这对于源代码信息的控制是非常重要的,其使用方法是:
#pragma message(消息文本)
当编译器遇到这条指令时,就在编译输出窗口中将消息文本显示出来。
另外一个使用比较多得pragma参数是code_seg.格式如:
#pragma code_seg([“section_name”[,section_class]])
它能够设置程序中函数代码存放的代码段,在开发驱动程序的时候就会使用到它。
参数once,可保证头文件被编译一次,其格式为:
#pragma once
只要在头文件的最开始加入这条指令就能够保证头文件被编译一次。
4、产生错误信息命令 #error
#error命令强制编译器停止编译,并输出一个错误信息,主要用于程序调试。其使用如下:
#error 信息错误
注意,错误信息不用双括号括起来。当遇到#error命令时,错误信息将显示出来。
例如,以下编译预处理器命令判断预定义宏__STDC__,如果其值不为1,则显示一个错误信息,提示程序员该编译器不支持ANSI C标准。
#if __STDC__!=1
#error NOT ANSI C
#endif
六、内联函数
在使用#define定义带参数宏时,在调用函数时,一般需要增加系统的开销,如参数传递,跳转控制,返回结果等额外操作需要系统内存和执行时间。而使用带参数宏时,通过宏替换可再编译前将函数代码展开导源代码中,使编译后的目标文件含有多段重复的代码。这样做,会增加程序的代码量,都可以减少执行时间。
在C99标准钟,还提供另外一种解决方法:使用内联函数。
在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替代。显然,这种做法不会产生转去转回得问题。都是由于在编译时将函数体中的代码被替代到程序中,因此会增加目标代码量,进而增加空间的开销,而在时间开销上不像函数调用时那么大,可见它是以增加目标代码为代码来换取时间的节省。
定义内联函数的方法很简单,只要在定义函数头的前面加上关键字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时,该函数在编译时会将以上代码复制过来,而不是像一般函数那样是运行时被调用。
内联函数具有一般函数的特性,它与一般函数所不同之处在于函数调用的处理。一般函数进行调用时,要讲程序执行权转导被调函数中,然后再返回到调用到它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换。在使用内联函数时,应该注意如下几点:
● 在内联函数内部允许用循环语句和开关语句。
● 内联函数的定义必须出现在内联函数第一次被调用之前。
其实,在程序中声明一个函数为内联时,编译以后这个函数不一定是内联的,
即程序只是建议编译器使用内联函数,但是编译器会根据函数情况决定是否使用内联,所以如果编写的内联函数中出现循环或者开关语句,程序也不会提示出错,但那个函数已经不是内联函数了。
一般都是讲一个小型函数作为内联函数。
大家如果对编程感兴趣,想了解更多的编程知识,解决编程问题,咨询编程学习,可以关注我们的微信公众号:程序员互动联盟(coder_online),这里有java高手、C++/C高手、windows/Linux高手等你来。
相关推荐
- 墨尔本一华裔男子与亚裔男子分别失踪数日 警方寻人
-
中新网5月15日电据澳洲新快网报道,据澳大利亚维州警察局网站消息,22岁的华裔男子邓跃(Yue‘Peter’Deng,音译)失踪已6天,维州警方于当地时间13日发布寻人通告,寻求公众协助寻找邓跃。华...
- 网络交友须谨慎!美国犹他州一男子因涉嫌杀害女网友被捕
-
伊森·洪克斯克(图源网络,侵删)据美国广播公司(ABC)25日报道,美国犹他州一名男子于24日因涉嫌谋杀被捕。警方表示,这名男子主动告知警局,称其杀害了一名在网络交友软件上认识的25岁女子。雷顿警...
- 一课译词:来龙去脉(来龙去脉 的意思解释)
-
Mountainranges[Photo/SIPA]“来龙去脉”,汉语成语,本指山脉的走势和去向,现比喻一件事的前因后果(causeandeffectofanevent),可以翻译为“i...
- 高考重要考点:range(range高考用法)
-
range可以用作动词,也可以用作名词,含义特别多,在阅读理解中出现的频率很高,还经常作为完形填空的选项,而且在作文中使用是非常好的高级词汇。...
- C++20 Ranges:现代范围操作(现代c++白皮书)
-
1.引言:C++20Ranges库简介C++20引入的Ranges库是C++标准库的重要更新,旨在提供更现代化、表达力更强的方式来处理数据序列(范围,range)。Ranges库基于...
- 学习VBA,报表做到飞 第二章 数组 2.4 Filter函数
-
第二章数组2.4Filter函数Filter函数功能与autofilter函数类似,它对一个一维数组进行筛选,返回一个从0开始的数组。...
- VBA学习笔记:数组:数组相关函数—Split,Join
-
Split拆分字符串函数,语法Split(expression,字符,Limit,compare),第1参数为必写,后面3个参数都是可选项。Expression为需要拆分的数据,“字符”就是以哪个字...
- VBA如何自定义序列,学会这些方法,让你工作更轻松
-
No.1在Excel中,自定义序列是一种快速填表机制,如何有效地利用这个方法,可以大大增加工作效率。通常在操作工作表的时候,可能会输入一些很有序的序列,如果一一录入就显得十分笨拙。Excel给出了一种...
- Excel VBA入门教程1.3 数组基础(vba数组详解)
-
1.3数组使用数组和对象时,也要声明,这里说下数组的声明:'确定范围的数组,可以存储b-a+1个数,a、b为整数Dim数组名称(aTob)As数据类型Dimarr...
- 远程网络调试工具百宝箱-MobaXterm
-
MobaXterm是一个功能强大的远程网络工具百宝箱,它将所有重要的远程网络工具(SSH、Telnet、X11、RDP、VNC、FTP、MOSH、Serial等)和Unix命令(bash、ls、cat...
- AREX:携程新一代自动化回归测试工具的设计与实现
-
一、背景随着携程机票BU业务规模的不断提高,业务系统日趋复杂,各种问题和挑战也随之而来。对于研发测试团队,面临着各种效能困境,包括业务复杂度高、数据构造工作量大、回归测试全量回归、沟通成本高、测试用例...
- Windows、Android、IOS、Web自动化工具选择策略
-
Windows平台中应用UI自动化测试解决方案AutoIT是开源工具,该工具识别windows的标准控件效果不错,但是当它遇到应用中非标准控件定义的UI元素时往往就无能为力了,这个时候选择silkte...
- python自动化工具:pywinauto(python快速上手 自动化)
-
简介Pywinauto是完全由Python构建的一个模块,可以用于自动化Windows上的GUI应用程序。同时,它支持鼠标、键盘操作,在元素控件树较复杂的界面,可以辅助我们完成自动化操作。我在...
- 时下最火的 Airtest 如何测试手机 APP?
-
引言Airtest是网易出品的一款基于图像识别的自动化测试工具,主要应用在手机APP和游戏的测试。一旦使用了这个工具进行APP的自动化,你就会发现自动化测试原来是如此简单!!连接手机要进行...
- 【推荐】7个最强Appium替代工具,移动App自动化测试必备!
-
在移动应用开发日益火爆的今天,自动化测试成为了确保应用质量和用户体验的关键环节。Appium作为一款广泛应用的移动应用自动化测试工具,为测试人员所熟知。然而,在不同的测试场景和需求下,还有许多其他优...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)