Chinaunix首页 | 论坛 | 博客
  • 博客访问: 303442
  • 博文数量: 69
  • 博客积分: 3093
  • 博客等级: 中校
  • 技术积分: 626
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-17 13:48
文章分类

全部博文(69)

文章存档

2011年(27)

2010年(11)

2009年(31)

分类: C/C++

2009-08-20 18:02:09

预处理:
预处理功能是C语言特有的功能,它是在对源程序正式编译前由预处理程序完成的。程序员在程序中用\\
预处理命令来调用这些功能。\\
______使用预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计。\\

===宏定义:===
1. 无参宏定义:(无参宏的宏名后不带参数)
    定义形式:#define  标识符  字符串   -->字符串可以是常量,表达式,格式串
源程序在编译时,将先由预处理程序进行宏替换,然后再进行编译\\
宏定义注意事项:
    1.  宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,
        字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查,如有错
        误,只能在编译已被宏展开后的源程序时发现
    2.  宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
    3.  宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束,如要终止其作用域可以使用#undef命令。
    4.  宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换-->类似字符串
    5.  宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。
    6.  习惯上宏名用大写字母表示,以便于与变量区别,但也允许用小写字母
    7.  可以宏定义表示数据类型,使书写方便。
    8.  对输出格式作宏定义可以减少书写麻烦,便于调试程序。

2. 带参宏定义:
   定义形式:#define 宏名(形参表)  字符串
   调用形式: 宏名(实参)
   例如:
        #define M(y) y*y+3*y /*宏定义*/
        ……
        k=M(5); /*宏调用*/
        ……
   在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:k=5*5+3*5

带参宏定义注意事项:
  1.  带参宏定义中,宏名和形参表之间不能有空格出现。
  2.  带参宏定义中,形参不分配内存单元,因此不必作类型定义,而实参需要做类型说明
  3.  在宏定义中的形参是标识符,而在宏调用中的实参可以是表达式。
    #define SQ(y) (y)*(y)
    main(){
    int a,sq;
    printf("input a number: ");
    scanf("%d",&a);
    sq=SQ(a+1);
    printf("sq=%d\n",sq);
    }
    上例中第一行为宏定义,形参为y。程序第七行宏调用中实参为a+1,是一个表达式,在宏展开时,
        用a+1代换y,再用(y)*(y) 代换SQ,得到如下语句:
    sq=(a+1)*(a+1);
    这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再赋予形参。而宏代换中对实参表
        达式不作计算直接地照原样代换。
  4.  在宏定义中,字符串内的形参通常要用括号括起来以避免出错。
  5.  带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。
  6.  宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内。看下面的例子。
      #define SSSV(s1,s2,s3,v) s1=l*w;s2=l*h;s3=w*h;v=w*l*h;
      main(){
      int l=3,w=4,h=5,sa,sb,sc,vv;
      SSSV(sa,sb,sc,vv);
      printf("sa=%d\nsb=%d\nsc=%d\nvv=%d\n",sa,sb,sc,vv);
      }
  程序第一行为宏定义,用宏名SSSV表示4个赋值语句,4 个形参分别为4个赋值符左部的变量。
  在宏调用时,把4个语句展开并用实参代替形参。使计算结果送入实参之中。
  为了避免宏代换时发生错误,宏定义中的字符串应加括号,字符串中出现的形式参数两
  边也应加括号。

==宏定义表示数据类型与typedef定义数据说明符的区别:==
宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名,被命名的标识符具有类型定义说明的功能。

请看下面的例子:
    #define PIN1 int *
    typedef (int *) PIN2;
    从形式上看这两者相似, 但在实际使用中却不相同。
    下面用PIN1,PIN2说明变量时就可以看出它们的区别:
    PIN1 a,b;在宏代换后变成:
    int *a,b;
    表示a是指向整型的指针变量,而b是整型变量。
    然而:
    PIN2 a,b;
表示a,b都是指向整型的指针变量。因为PIN2是一个类型说明符。
由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。

===文件包含:===
文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一\\
个目标文件。\\
1.  文件包含包括""和<>:\\
""号使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。用户编程时\\
可根据自己文件所在的目录来选择某一种命令形式。\\
<>号:使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文\\
件目录去查找;\\
文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。\\

===条件编译:===

条件编译允许只编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率。

  #define NUM ok
    #ifdef NUM
       printf.....1
   #else
      printf......2
   #endif

如果ifdef指定位置数据被#define定义过,则执行程序段1否则执行程序段2\\
如果ifndef指定位置没有被#define定义过,则执行程序段1否则执行程序段2\\

===例子:===

经常会在cpp文件中见到类似于下面的定义:

  #ifndef A
  #define A
  #ifdef /_/_cpluspluss //此处为两个下划线
  extern "C"{
  #endif
  void cpp_fun();
  #ifdef /_/_cplusplus //此处为两个下划线
  }
  #endif
  #endif

其中/_/_cplusplus(此处为两个下划线)是C++编译器的保留宏定义,extern“C”告诉C++编译器括弧里边的\\
东西按照C的obj文件格式编译,链接的话按照C的命名规则去找。
总结:C和C++对函数的处理方式是不同的,extern "C"是使C++能够调用C写的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。
阅读(1504) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~