首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

宏和预处理器详述(2)

宏和预处理器详述(2)

宏定义需要注意的问题
1.宏是预处理阶段的替换(expansion),不进行计算,所以要时刻把()加上.拿上面定义的一个例子来看:
bar.c

#define ADD(foo) foo+10
int i = 2 * ADD(3);

语句会被替换成:
int i = 2 * foo+10;
  这样就错误了.本意是要3+10,然后再乘以2,结果为26,现在变成了30了.
#define ADD(foo) (foo+10)
  最好把参数全部加上(),对于这个例子,没有必要,但是对其他的例子就很有必要了:
#define MUL(foo, egg) foo*egg
MUL(2+3,4+5);
期望的结果是(2+3)*(4+5)=45,结果却成了2+3*4+5=19.
合理的定义方式是:
#define MUL(foo, egg) ((foo) * (egg))

2.宏是否可以用来定义注释.
#define HEAD_COMMENT /*
#define END_COMMENT */

  答案是否定的.注释的处理在预处理指令处理之前,也就是说在define指令被处理之前注释已经不存在,如果在预处理指定处理过后又出来了定义的话,编译器一定会不认识.  
  
  Preprocessor(预处理器),在计算机科学中指的是一个处理代码输入并且把输出做为另外一个程序输入的程序,它也是一个程序.参看:http://en.wikipedia.org/wiki/PreprocessorGNU的预处理器可以处理C/C++/Objective-c,因为都和C沾边(或者就是从开始遗留下来的习惯)所以就叫C PreProcessor(cpp 不是c plusplus:-) )

  CPP处理预处理指令,有#include,#define(undef),#if(ifdef,ifndef,else if,elif,endif),#error,#line, #pragma,#,##,当然预处理也处理注释(comment),而且优先于预处理指令.
1.文件包含(file inclusion)

#include指令

#include <stdio.h>      从标准路径搜索stdio.h
#include "nids.h"
  从当前目录开始搜索nids.h如果找不到再到命令行参数指定的目录寻找最后是标准目录下寻找.


2.宏定义(macros defination)
前述.

3.条件编译(conditinal compilation)

#if __STDC__ == 1
#if defined FREEBSD
#if !defined FREEBSD
#endif

#ifdef FREEBSD
#else if
#define LINUX
#endif

4.错误产生(error generation)
#error this line shouldnt be reached


5.行号控制(line control)
#line 299 "ip.c"  下一行是ip.c的299行
#line 299         下一行是本文件的299行


6 #,##
#和##常常用于宏定义里,这两个是预处理运算符,不是指令,因为预处理指令不能用于宏定义.就像C99添加的_Pragma操作符.

#define tempfile(dir) #dir "/%s"
tempfile(/usr/tmp)被扩展成  "/usr/tmp" "/%s",也就是 "/usr/tmp/%s"
#把宏参数字符串化(C语言表示的字符串),而且这个的"优先级"比较高.
看一个来自cpp手册的例子:
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)       由于有#,表示参数首先被字符串化,所以不再有任何扩展.

→ "foo"
xstr (foo)      没有#,所以参数被扩展.

→ xstr (4)

→ str (4)

→ "4"

解释:
s is stringified when it is used in str, so it is not macro-expanded first. Buts is an ordinary argument to xstr, so it is completely macro-expanded before xstr itself is
expanded . Therefore, by thetime str gets to its argument, it has already been macro-expanded.

#define cat(x,y) x##y
cat(2,3)   扩展为23
cat(wolf,python) 扩展为wlfpython
##把tokens连接起来(tokens concatenation)
通常##两边的tokens可以是标识符,数字或者运算符,不可以是C语言表示的字符串.
比如cat("2","3")是错误的.

7.#pragma
#pragma用于向编译器提供信息.(由于是指令,所以无法用于宏定义,C99定义了_Pragma运算符)

#pragma once 可以用于防止头文件被重复包含(另外一种方式是使用条件编译)

8.空指令 #
#后面仅跟着一个换行符,就是一个空指令,什么也不做,在预处理阶段没有动它.
继承事业,薪火相传
返回列表