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

C语言深度解剖读书笔记(3.预编译处理)

C语言深度解剖读书笔记(3.预编译处理)

本节知识点:1.编译过程的简介:

   预编译:
a.处理所有的注释,以空格代替。
b.将所以#define删除,并展开所有的宏定义,字符串替换。
c.处理条件编译指令#if,#ifdef,#elif,#else,#endif
d.处理#include,并展开被包含的文件,把头文件中的声明,全部拷贝到文件中。
e.保留编译器需要使用的#pragma指令、
怎么样观察这些变化呢?最好的方法就是在GCC中,输入预处理指令,可以看看不同文件经过预处理后变成什么样了,预处理指令:gcc -E file.c -o file.i   注意:-C -E一起使用是预编译的时候保留注释。
   编译:
a.对预处理文件进行一系列词法分析,语法分析和语义分析
                词法分析:主要分析关键字,标示符,立即数等是否合法
                语法分析:主要分析表达式是否遵循语法规则
                语义分析:在语法分析的基础上进一步分析表达式是否合法
b.分析结束后进行代码优化生成相应的汇编代码文件               编译指令:gcc -S  file.c  -o  file.s
   汇编:
汇编器将汇编代码转变为机器可以执行的指令,每个汇编语句几乎都对应一条机器指令,其实机器指令就是机器码,就是2进制码。汇编指令:gcc  -c  file.c  -o file.o  注意:-c是编译汇编不连接。
   链接:
再把产生的.o文件,进行链接就可以生成可执行文件。连接指令:gcc  file.o  file1.o  -o  file  这句指令是链接file.o和file1.o两个编译并汇编的文件,并生成可执行文件file。
链接分两种:静态链接和动态链接,静态链接是在编译器完成的,动态链接是在运行期完成的。静态链接的指令是:gcc -static file.c -o file对于一些没有动态库的嵌入式系统,这是常用的。
一般要想通过一条指令生成可执行文件的指令是:   gcc file.c  -o  file
   资料:这里面说到了很多关于gcc的使用的问题,我提供一个gcc的学习资料,个人觉得还不错,也不长,就是一个txt文档,很全面。资源下载地址http://download.csdn.net/detail/qq418674358/6041183   Ps:嘿嘿,设了一个下载积分,因为真的是没分用了!希望大家见谅哈!

2.c语言中的预处理指令:#define、#undef(撤销已定义过的宏名)、#include、#if、#else、#elif、#endif、#ifdef、#ifndef、#line、#error、#pragma。还有一些ANSI标准C定义的宏:__LINE__、__FILE__、__DATA__、__TIME__、__STDC__。这样使用printf("%s\n",__TIME__);     printf(__DATE__);
一个#undef的例子:
[cpp] view plaincopy


  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>


  • #define X 2
  • #define Y X*2
  • #undef X
  • #define X 3


  • int main()  
  • {  
  •     printf("%d\n",Y);  
  •     return 0;  
  • }  

这个输出的是6,说明了#undef的作用

3.宏定义字符串的时候:应该是 #define HELLO "hello world"  记住是双引号。还有就是一切宏都是不能有分号的,这个一定要切忌!!!
4.宏与函数的比较:
   a.宏表达式在预编译期被处理,编译器不知道有宏表达式存在
   b.宏表达式没有任何的"调用"开销
   c.宏表达式中不能出现递归定义
5.为什么不在头文件中定义全局变量:
如果一个全局变量,想要在两个文件中,同时使用,那这两个文件中都应该#include这个头文件,这样的话就会出现重复定义的问题。其实是重名的问题,因为#include是分别在两个文件中展开的,试想一下,如果在两个文件中的开始部分,都写上int  a = 10;  是不是也会报错。可能你会说那个#ifndef不是防止重复定义吗?是的 ,那是防止在同一个文件中,同时出现两次这个头文件。现在是两个文件中,所以都要展开的。全局变量就重名了!!!所以 对于全局变量,最好是定义在.c文件中,不要定义在头文件中。
6.#pargma pack 设置字符对齐,看后面一节专门写字符对齐问题的!!!
7.#运算符(转换成字符串):
    假如你希望在字符串中包含宏参数,那我们就用#号,它把语言符号转换成字符串。
    #define SQR(x) printf("the "#x"lait %d\n",((x)*(x)));
    SQR(8)
    输出结果是:the 8 lait 64   这个#号必须使用在带参宏中

有个小例子:
[cpp] view plaincopy


  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>
  • /*在字符串中  加入宏参用的*/
  • #define SCAN(N,String) scanf("%"#N"s",String);  //N是截取的个数  String是存储的字符串
  • int main()  
  • {  
  •     char dd[256];  
  •     SCAN(3,dd) //记得没有分号哈  自定义 任意格式输入的scanf  截取输入的前三个
  •     printf("%s\n",dd);  
  •     return 1;  
  • }  

8.##运算符(粘合剂)
    一般用于粘贴两个东西,一般是用作在给变量或函数命名的时候使用。如#define XNAME(n) x##n
    XNAME(8)为8n   这个##号可以使用在带参宏或无参宏中
下面是一个##运算符的小例子,代码如下:
[cpp] view plaincopy


  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>

  • #define BL1 bb##ll##1

  • #define BL(N) bbll##N
  • int main()  
  • {  
  •     int BL1=10;  

  •     int BL(4)=15;  
  •     printf("%d\n",bbll1);  

  •     printf("%d\n",bbll4);  
  •     return 1;  
  • }  

注意:#号和##号都必须只能在宏定义中使用,不能使用在其他地方
9.其实预编译这块还有一些,不常用到的预编译指令,也是盲点,但是不难理解,用到的时候查查就好。比如说#line、#error、#warning等。
返回列表