c的预处理器

</pre>当我们写完c的源代码后,不管是在Linux环境下输入命令行手动编译链接程序,还是在IDE集成环境下(列如vs)中点击生成,或者直接运行程序,对于源码处理的第一步,就是预处理器来对源代码处理。</p><p>故,第一步要干的事(也就是预处理器要干的事)<span style="color:#cc0000;">:删除注释,插入被#include指令包含的文件内容,定义和替换由#define指令定义的符号,根据条件编译指令来选择编译内容</span>。</p><p>1.预定义符号:<span style="color:#990000;background-color: rgb(255, 255, 255);">由预处理器定义的符号(值类型,字符串常量,十进制数字常量)</span></p><p>      常见的:</p><p><span style="white-space:pre">	</span>__FILE__ :被编译的源文件的名称</p><p><span style="white-space:pre">	</span>__LINE__:文件当前的行号</p><p><span style="white-space:pre">	</span>__TIME__:被编译的时间</p><p><span style="white-space:pre">	</span>__DATE__:被编译的日期</p><p><span style="white-space:pre">	</span>__STDC__:看编译器是否遵循ANSI C标准,若遵循,则值为1,否则未定义</p><p>实验源码:(vs2010下)</p><p></p><pre name="code" class="cpp">#include <stdio.h>
int main()
{
<span style="white-space:pre">	</span>const char * fileName=__FILE__;
<span style="white-space:pre">	</span>const char * date=__DATE__;
<span style="white-space:pre">	</span>const char * time=__TIME__;
<span style="white-space:pre">	</span>//const char * stdc=__STDC__;
<span style="white-space:pre">	</span>printf("%s\n",fileName);
<span style="white-space:pre">	</span>printf("%s\n",date);
<span style="white-space:pre">	</span>printf("%s\n",time);
#if (_MSC_VER==1600)
<span style="white-space:pre">	</span>printf_s("编译器版本vc10\n");
#endif
<span style="white-space:pre">	</span>return 0;
}
我使用的vs2010,编译器版本为vc10,__STDC__是未定的,可见此编译器不是完全遵循ANSI C标准。其余的预定义符号可正常打印。


2.#define讲解

  1.纯粹的文本替换:#define name  something

列如:常见的为静态数组确定一个最大容量:#define MAXSIZE 1000

    2.宏定义:#define name(参数列表)     something

                列如:define DOUBLE(x)  ((x)+(x))     //此括号最后都打上,避免因字符串替换导致运算的优先级改变等不容易发现的错误。

           

4.宏与函数的对照

        1.宏不局限于具体类型(宏与类型无关),而函数的值类型必须明确

        举例:#define malloc(n,type)  \

((type*)malloc((n)*sizeof(type)))

                 宏可以做到此种效果,不同的type分配出不同种类的内存空间,而函数却做不到。(题外话,最后的效果有点类似于java的反射机制)

        2.宏的速度一般都要快些,因为调用函数时需要阻塞等待,保留现场,调用需要时间,调用的函数运行又需要花时间,返回结果,回复现场又需要花时间,相比宏直接嵌入源码运行,时间上来说开销大些。

         3.每个使用宏的地方,都需要把宏定义代码插入到程序中,代码有重复性,没有函数的复用方便,导致程序源码的长度会大大增加。


5.根据条件来编译

   举例:

   #if

do something

   #elif

do something

   #endif

do something

    

6.常用的预处理指令

#if defined(A)  //等价于 #ifdef(A) ,若是否定,则为  #if  !defined(A)  或者#ifndef(A)

do something about A

#elif defined(B)

        do something about B

#else

#error   errorMsg

#endif


以下摘自《c和指针》的编程经验总结:

 1.避免使用#define指令定义可以用函数实现的很长序列代码

2.在那些对表达式求值的宏中,每个宏参数出现的地方都应该加上括号,并且在整个宏定义的两边也加上括号

3.避免使用#define宏创建一种新语言。

4.采用命名约定,使程序员很容易看出某个标识符是否为#define宏

5.只要适合就应该使用文件包含,不必担心它的额外开销

6.头文件只应该包含一组函数和(或)数据的申明

7.把不同集合的申明分离到不同的头文件中可以改善信息隐藏

8.嵌套的#include 文件使我们很难判断文件之间的依赖关系



编程题目:

 1.编写一个用于调试的宏,打印出任意的表达式。它被调用时应该接受两个参数,第一个是printf格式吗,第2个是需要打印的表达式

我编写的代码:

第一步:添加头文件print.h

第二步:#ifndef __PRINT_H

                #define PRINT(x,y)  \

                   printf(x,(y))

               #endif

标准答案:

#ifndef  __PRINT__H
#define DEBUG_PRINT( fmt, expr ) \
printf( "File %s, line %d: %s = " \
fmt "\n", \
__FILE__, __LINE__, \
#expr, expr )
#endif

2.

我的答案:

先定义一个var_print.h头文件,其中的代码

#ifndef VAR_PRINT
	#if defined(OPTION_LONG)
		#define  print_ledger(x) print_ledger_long(x)
	#elif defined(OPTION_DETAILED)
		#define  print_leger(x) print_ledger_detailed(x)
	#else 
		#define  print_ledger(x) print_ledger_default(x)
	#endif
#endif


#include<stdio.h>


void print_ledger_long(int x)
{
	printf("print_ledger_long:%d\n",x);
}


void print_ledger_detailed(int x)
{
	printf("print_ledger_detailed:%d\n",x);
}


void print_ledger_default(int x)
{
	printf("print_ledger_default:%d\n",x);
}

mian.cpp

敲打

#define OPTION_LONG
#include "var_print.h"

int main()
{
	int a=3;
	print_ledger(a);
	return 0;
}
  程序成功运行


3.

步骤1:cpu_types.h

#ifndef CPU_TYPES_H
/************************************************************************/
/* 系统类型定义                                                                     */
/************************************************************************/
#define CPU_VAX 0
#define CPU_6000 1
#define CPU_68020 2
#define CPU_80386 3
#define CPU_6809 4
#define CPU_6502 5
#define CPU_U3B2 6
#define CPU_UNKNOW 7


#endif  

cpu_types.c
#include"cpu_types.h"
#include<stdio.h>
int  cpu_type();
int main()
{
     int a=cpu_type();
    printf("%d\n",a);
    return 0;
}

int  cpu_type()
{
#if defined(VAX)
    return  CPU_VAX;
#elif defined(M68000)
    return CPU_6000;
#elif defined(M68020)
    return CPU_68020;
#elif defined(I80386)
    return CPU_80386;
#elif defined(X6809)
    return CPU_6809;
#elif defined(X6502)
    return CPU_6502;
#elif defined(U3B2)
    return CPU_U3B2;
#else 
    return CPU_UNKNOW;
#endif
}

以上是书籍给出的标准答案,但是发现“如果超过一个符号被定义,那么其结果是未定义的这个条件”不符合标准。


   


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五癫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值