c中预处理简谈

宏定义
根据宏定义中是否有参数,可以将宏定义分为不带参数的宏定义和带参数的宏定义。
1.不带参数的宏定义
宏定义指令#define用来定义一个标识符和一个字符串,以这个标识符来代表这个字符串,在程序中每次遇到该标识符时就用所定义的字符串替换它。宏定义的作用相当于给指定的字符串起一个别名。
    一般形式:
    #define    宏名    字符串
    **“#”表示这是一条预处理命令。
    **宏名是一个标识符,必须符合c语言标识符的规定。
    **字符串这里可以是常数、表达式、格式字符串等。
eg:#define PI 3.14159
使用#define进行宏定义的好处是需要改变一个常量的时候只需要改变#define命令行,整个程序的常量都会改变,大大提高了程序的灵活性。宏名要简单且意义明确,一般习惯用大写字母表示以便与变量名相区别。
    注意:宏定义不是c语句,不需要在行末加分号。宏名定义后,即可成为其他宏名定义中的一部分。
         在编写程序时通常将所有的#define放到文件的开始处或独立的文件中,而不是将它们分散到整个程序中。
重点强调:
    **如果在字符串中含有宏名,则不进行替换
    **如果串长于一行,可以在该行末尾用一反斜杠“\”续行
    **#define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到此源文件结束。
    **可以用#undef命令终止宏定义的作用域
    **宏定义用于预处理命令,它不同于定义的变量,只作字符替换,不分配内存空间。

2.带参数的宏定义
带参数的宏定义不是简单的字符串替换,还要进行参数替换。
    一般形式:
    #define    宏名(参数表) 字符串
eg:#define MIX(a,b) ((a)*(b)+(b))
用宏代替实在的函数的一个好处是宏替换增加了代码的速度,因为不存在函数调用。但增加速度也有代价:由于重复编码而增加了程序长度。
重点强调:
    **宏定义时参数要加括号,如不加括号,则有时结果是正确的,有时结果却时错误的。
    **宏扩展必须使用括号,来保护表达式中低优先级的操作符,以确保调用时达到想要的效果。
    **对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替#define命令行中的形参。
    **在宏定义时,在宏名与带参数的括号之间不可以加空格,否则会将空格以后的字符都作为替代字符串的一部分。
    **在带参宏定义中,形式参数不分配内存单元。因此不必作类型定义。


3.#include指令
在一个源文件中使用#include指令可以将另一个源文件的全部内容包含进来,也就是将另外的文件包含到本文件之中。#include使编译程序将另一源文件嵌入带有#include的源文件,被读入的源文件必须用双引号或尖括号括起来。
    eg:
    #include <stdio.h>
    #include "stdio.h"
尖括号和双引号的形式区别:
    用尖括号时,系统到存放c库函数头文件所在的目录中寻找要包含的文件,这为标准方式;用双引号时,系统先在用户当前目录中寻找要包含的文件,若找不到,再到存放c库函数头文件所在目录中寻找要包含的文件。通常情况下,如果为调用库函数用#include命令来包含相关的头文件,则用尖括号可以节省查找的时间。如果要包含的是用户自己编写的文件,一般用双引号,用户自己编写的文件通常是在当前目录中。如果文件不在当前目录中,双引号可给出文件路径。
经常用在文件头部的被包含的文件称为“标题文件”或“头部文件”,一般以.h为后缀,eg:file.h
    一般情况下将如下内容放到.h文件中:
    **宏定义
    **结构、联合和枚举声明
    **typedef声明
    **外部函数声明
    **全局变量声明
使用文件包含为实现程序修改提供了方便,当需要修改一些参数时不必修改每个程序,只需修改一个文件(头部文件)即可。
    关于“文件包含”有以下几点需要注意:
    **一个#include命令只能指定一个被包含的文件。
    **文件包含是可以嵌套的,即在一个被包含文件中还可以包含另一个被包含文件。
    **若file1.c中包含文件file2.h,那么在预编译后就成为一个文件而不是两个文件,这时如果file2.h中有全局静态变量,则该全局变量在file1.c文件中也有校,这时不需要再用extern声明。


3.条件编译
使用条件编译可以方便地处理程序的调试版和正式版,同时还会增加程序的可移植性。
    a.#if命令
    if的基本含义是:如果#if指令后的参数表达式为真,则编译#if到#endif之间的程序段,否则跳过这段程序。#endif指令用来表示#if段的结束。
    一般形式:
        #if 常数表达式
            语句段
        #endif
    如果常数表达式为真,则该段程序被编译,否则跳过不编译。
#else的作用是为#if为假时提供另一种选择,#elif指令用来建立一种“如果…或者如果…”这样阶梯状多重编译操作选择,这与多分支if语句的else if类似。
    #elif的一般形式:
        #if 表达式
        语句段
        #elif 表达式1
        语句段
        #elif 表达式2
        语句段
        ……
        #elif 表达式n
        语句段
        #endif
    b.#ifdef及#ifndef命令
若只需要知道某个符号常量是否被定义则可使用#ifdef和#ifndef命令,分别表示为“如果有定义”及“如果无定义”。
    #ifdef的一般形式:
        #ifdef 宏替换名
        语句段
        #endif
其含义是:如果宏替换名已被定义过,则对“语句段”进行编译;如果未定义#ifdef后面的宏替换名,则不对语句段进行编译。
    #ifdef与#else连用,构成的一般形式:
  #ifdef 宏替换名
        语句段
        #else
        语句段2
        #endif
其含义是:如果宏替换名已被定义过,则对“语句段1”进行编译;如果未定义#ifdef后面的宏替换名,则对语句2进行编译。
    
    #ifndef的一般形式:
        #ifndef 宏替换名
        语句段
        #endif
其含义是:如果未定义#ifndef后面的宏替换名,则对“语句段1”进行编译;如果定义#ifndef后面的宏替换名,则不执行语句段。同样,#ifndef也可以与#else连用。

    c.#undef命令
使用#undef命令可以删除事先定义了的宏定义。
    #undef命令的一般形式:
        #undef 宏替换名
说明:#undef的主要目的是将宏名句限在仅需要它们的代码段中。
    d.#line命令
line命令改变_LINE_与_FILE_的内容,_LINE_存放当前编译行的行号,_FILE_存放当前编译的文件名。
    #line的一般形式:
        #line 行号["文件名"]
    e.#pragma命令
#pragma命令的作用是设定编译器的状态,或者指示编译器完成一些特定的动作。
    #pragma指令的一般形式:
        #pragma 参数
参数的分类:
    message参数:能够在编译信息输出窗口中输出相应的信息
    code_seg参数:设置程序中函数代码存放的代码段
    once参数:保证头文件被编译一次
    f.预定义宏名
    _LINE_:其含义是当前被编译代码的行号
    _FILE_:其含义是当前源程序的文件名称
    _DATE_:其含义是当前源程序的创建日期
    _TIME_:其含义是当前源程序的创建时间
    _STDC_:其含义是用来判断当前编译器是否为标准C,若其值为1则表示符合标准C,否则不是标注C。
ps:宏名的书写比较特别,书写时两边都要由两个下划线构成。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值