搜索
bottom↓
回复: 18

把常用的预处理命令总结如下

[复制链接]

出0入0汤圆

发表于 2008-6-20 16:08:09 | 显示全部楼层 |阅读模式
我们可以在C源程序中插入传给编译程序的各中指令,这些指令被称为预处理器指令,它们扩充了程序设计的环境。现把常用的预处理命令总结如下:
1.      预处理程序
按照ANSI标准的定义,预处理程序应该处理以下指令:
#if
#ifdef
#ifndef
#else
#elif
#endif
#define
#undef
#line
#error
#pragma
#include
显然,上述所有的12个预处理指令都以符号#开始,,每条预处理指令必须独占一行。
2.      #define
#define指令定义一个标识符和一个串(也就是字符集),在源程序中发现该标识符时,都用该串替换之。这种标识符称为宏名字,相应的替换称为宏代换。一般形式如下:
#define macro-name char-sequence
这种语句不用分号结尾。宏名字和串之间可以有多个空白符,但串开始后只能以新行终止。
例如:我们使用LEFT代表1,用RIGHT代表0,我们使用两个#define指令:
#define LEFT 1
#define RIGHT 0
每当在源程序中遇到LEFT或RIGHT时,编译程序都用1或0替换。
定义一个宏名字之后,可以在其他宏定义中使用,例如:
#define ONE 1
#define TWO ONE+ONE
#define THREE ONE+TWO
宏代换就是用相关的串替代标识符。因此,如果希望定义一条标准错误信息时,可以如下定义:
#define ERROR_MS “Standard error on input \n”
如果一个串长于一行,可在行尾用反斜线”\”续行,如下:
#define LONG_STRING “This is a very very long \
String that is used as an example”
3.      #error
#error指令强制编译程序停止编译,它主要用于程序调试。#error指令的一般形式是:
#error error-message
注意,宏串error-message不用双引号包围。遇到#error指令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。
4.      #include
程序中的#include指令要求编译程序读入另一个源文件。被读入文件的名字必须用双引号(“”)或一对尖括号(<>)包围,例如:
#include “stdio.h”
#include <stdio.h>
都使C编译程序读入并编译头文件以用于I/O系统库函数。
包含文件中可以包含其他#include指令,称为嵌套包含。允许的最大嵌套深度随编译器而变。
文件名被双括号或尖括号包围决定了对指定文件的搜索方式。文件名被尖括号包围时,搜索按编译程序作者的定义进行,一般用于搜索某些专门放置包含文件的特殊目录。当文件名被双括号包围时,搜索按编译程序实时的规定进行,一般搜索当前目录。如未发现,再按尖括号包围时的办法重新搜索一次。
通常,绝大多数程序员使用尖括号包围标准的头文件,双引号用于包围与当前程序相关的文件名。

5.      条件编译指令
若干编译指令允许程序员有选择的编译程序源代码的不同部分,这种过程称为条件编译。
5.1#if、#else、#elif #endif
条件编译指令中最常用的或许是#if,#else,#elif和#endif。这些指令允许程序员根据常数表达式的结果有条件的包围部分代码。
#if的一般形式是:
#if constant-expression
Statement sequence
#endif
如#if后的常数表达式为真,则#if和#endif中间的代码被编译,否则忽略该代码段。#endif标记#if块的结束。

#else指令的作用与C语言的else相似,#if指令失败时它可以作为备选指令。例如:
#include <stdio.h>
#define MAX 100

Int main(void)
{
#if MAX>99
printf(“Compiled for array greater than 99.\n”);
#else
printf(“Complied for small array.\n”);
#endif
return 0;
}
注意,#else既是标记#if块的结束,也标记#else块的开始。因为每个#if只能写一个#endif匹配。

#elif指令的意思是“否则,如果”,为多重编译选择建立一条if-else-if(如果-否则-如果链)。如果#if表达式为真,该代码块被编译,不测试其他#elif表达式。否则,序列中的下一块被测试,如果成功则编译之。一般形式如下:
#if expression
Statement sequence
#elif expression1
Statement sequence
#elif expression2
Statement sequence
.
.
.
#elif expression
Statement sequence
#endif
5.2#ifdef和#ifndef
条件编译的另一个方法是使用编译指令#ifdef和#ifndef,分别表示“如果已定义”和“如果未定义”。#ifdef的一般形式如下:
#ifdef macro-name
Statement sequence
#endif
如果macro-name原先已经被一个#define语句定义,则编译其中的代码块。
#ifndef的一般形式是:
#ifndef macro-name
Statement sequence
#endif
如果macro-name当前未被#define语句定义,则编译其中的代码块。
#ifdef和#ifndef都可以使用#else或#elif语句。

#inlucde <stdio.h>
#define T 10

Int main(void)
{
#ifdef t
Printf(“Hi T\n”);
#else
Printf(“Hi anyone\n”);
#endif
#ifndef M
Printf(“M Not Defined\n”);
#endif

Return 0;
}
6.      #undef
#undef指令删除前面定义的宏名字。也就是说,它“不定义”宏。一般形式为:
#undef macro-name
7.      使用defined
除#ifdef之外,还有另外一种确定是否定义宏名字的方法,即可以将#if指令与defined编译时操作符一起使用。defined操作符的一般形式如下:
defined macro-name
如果macro-name是当前定义的,则表达式为真,否则为假。
例如,确定宏MY是否定义,可以使用下列两种预处理命令之一:
#if defined MY

#ifdef MY
也可以在defined之前加上感叹号”!”来反转相应的条件。例如,只有在DEBUG未定义的情况下才编译。
#if !defined DEBUG
Printf(“Final Version!\n”);
#endif
使用defined的一个原因是,它允许由#elif语句确定的宏名字存在。
8.      #line
#line指令改变__LINE__和__FILE__的内容。__LINE__和__FILE__都是编译程序中预定义的标识符。标识符__LINE__的内容是当前被编译代码行的行号,__FILE__的内容是当前被编译源文件的文件名。#line的一般形式是:
#line number “filename”
其中,number是正整数并变成__LINE__的新值;可选的“filename”是合法文件标识符并变成__FILE__的新值。#line主要用于调试和特殊应用。

9.      #pragma
#pragma是编译程序实现时定义的指令,它允许由此向编译程序传入各种指令。例如,一个编译程序可能具有支持跟踪程序执行的选项,此时可以用#pragma语句选择该功能。编译程序忽略其不支持的#pragma选项。#pragma提高C源程序对编译程序的可移植性。
10. 预处理操作符#和##
有两个预处理操作符:#和##,它们可以在#define中使用。
操作符#通常称为字符串化的操作符,它把其后的串变成用双引号包围的串。例如:
#include <stdio.h>
#define mkstr(s) #s
int main(void)
{
Printf(mkstr(I like C));

Return 0;
}

预处理程序把以下的语句:
Printf(mkstr(I like C));
变成
Printf(“I like C”);
操作符##把两个标记拼在一起,形成一个新标记。例如:
#include <stdio.h>
#define concat(a,a) a##b

int main(void)
{
Int xy = 10;
Printf(“%d”,concat(x,y));
Return 0;
}
预处理程序把以下语句:
Printf(“%d”,concat(x,y));
变成
Printf(“%d”,xy);
操作符#和##主要作用是允许预处理程序对付某些特殊情况,多数程序中并不需要。
11. 预定义宏
C规范了5个固有的预定义宏,它们是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__

__LINE__和__FILE__包含正在编译的程序的行号和文件名。
__DATE__和内容形如month/day/year(月/日/年)的串,代表源文件翻译成目标码的日期。
__TIME__中的串代表源代码编译成目标码的时间,形如hour:minute:second(时:分:秒)
如果__STDC__的内容是十进制常数1,则表示编译程序的实现符合标准C。


Over,呵呵,有点累,呵呵,希望对想了解C语言预处理命令的人有帮助。^-^

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2008-6-20 16:30:47 | 显示全部楼层
好东西,对初学习者来说是黄金呀

出0入0汤圆

发表于 2008-6-20 16:43:18 | 显示全部楼层
对这个比较晕,得认真学习一下。
收藏,谢谢!

出0入8汤圆

发表于 2008-6-20 17:59:51 | 显示全部楼层
好,扫盲

出0入0汤圆

发表于 2008-6-20 19:43:34 | 显示全部楼层
除了include define 用的最多以外,最有用的就要数#ifndef #endif,这些一般用于头文件,如果写过多文件的程序的兄弟们肯定会遇到过头文件定义的麻烦,有些重复定义,编译器不是警告就是报错。如果你在头文件使用了
#ifndef FIRST
#define FIRST
…………
所有语句
…………
#endif
此时即便你重复定义,但是编译器会检测FIRST有没有定义,如果定义了则不进行2次加载,如果没进行定义则进行加载,有效避免了重复定义。

注:以上是本人常用的几个定义,不代表其他人的观点!

出0入0汤圆

发表于 2008-7-8 15:48:51 | 显示全部楼层
谢谢

出0入50汤圆

发表于 2008-7-8 16:02:14 | 显示全部楼层
我怎么今天才看到如此好文啊?

以前除了会用include define 之外,啥都不会,看人家的程序也是云里雾里,这回得好好研究下了,马上排版,打印出来看看啦。

多谢楼主!

出0入0汤圆

发表于 2008-7-8 16:59:04 | 显示全部楼层
学习了~~~
谢谢~

出0入46汤圆

发表于 2008-7-8 17:30:13 | 显示全部楼层
好!

出0入0汤圆

发表于 2008-7-8 20:07:42 | 显示全部楼层
这个不顶对不起社会~

出0入0汤圆

发表于 2008-7-8 20:58:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-7-8 22:08:29 | 显示全部楼层
最近也想把些有用的程序整理成头文件,得看看!

出0入0汤圆

发表于 2013-3-12 16:57:27 | 显示全部楼层
好东西,学习了

出0入0汤圆

发表于 2013-3-12 16:57:43 | 显示全部楼层
好东西,学习了

出0入0汤圆

发表于 2013-3-12 17:24:33 来自手机 | 显示全部楼层
谢谢楼主......

出0入0汤圆

发表于 2016-11-27 17:45:12 | 显示全部楼层
如何重新预处理?有这个指令吗?

出0入0汤圆

发表于 2016-11-27 17:45:27 | 显示全部楼层
重新让单片机预处理

出0入0汤圆

发表于 2016-11-27 20:37:40 | 显示全部楼层
一直没找到这么全的说明   感谢分享哦   感觉##没准有大用

出0入0汤圆

发表于 2016-12-7 20:32:02 | 显示全部楼层
C深入越多,越发现预处理命令非常有用。。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 20:42

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表