zoukankan      html  css  js  c++  java
  • 编译过程

    编译过程简介:

     预编译:gcc -E file.c -o file.i

    处理注释,以空格代替

    将宏定义展开

    处理条件编译指令

    处理#include,展开被包含的文件

    保留编译器需要使用的#pragma指令

    编译: gcc -S file.i -o file.s

    对预处理文件进行词法分析,语法 分析,语义分析

    汇编:gcc -c file.s -o hello.o

    将汇编代码翻译成机器码

    链接:

    将各个模块之间的相互引用的部分处理好,使得各个模块之间能够正确的衔接。将各个独立的模块链接成可执行的程序

    静态链接:各个模块简单连接,编译期完成

    动态链接:共享库文件,运行期完成

    定义宏常量:

    #define定义宏常量,可以出现咋代码的任何地方;从定义行开始,之后的代码都可使用这个宏常量(不管是否在某个函数中定义)

    定义宏表达式:

     1 #include <stdio.h>
     2 int f1(int a, int b)
     3 {
     4     #define _MIN_(a,b) ((a)<(b) ? a : b)    
     5     return _MIN_(a, b);
     6 }
     7 int f2(int a, int b, int c)
     8 {
     9     return _MIN_(_MIN_(a,b), c);
    10 }
    11 int main()
    12 {
    13     printf("%d
    ", f1(2, 1));
    14     printf("%d
    ", f2(5, 3, 2));   
    15     return 0;
    16 }

    宏表达式的域:自定义行开始之后的所有代码都可以使用

    定义宏只能在一行中完成,(使用接续符换行)

    宏表达式与函数的对比:
    宏表达式在预编译的过程中被处理,编译器不知道宏表达式的存在;宏表达式用实参 完全代替形参,不进行任何运算;宏表达式没有任何的调用开销;宏表达式不能出现递归定义。

    #define func(n) ((n>0) ? func(n-1) : 0 ); //错误,递归定义宏

    #undef:用于结束宏的作用域

    条件编译的使用:

    条件编译是预编译指示命令,用于控制是否编译某段代码;执行行为类似:if else语句。

    1 #if (exp1)
    2 ....;
    3 #else
    4 ...;
    5 #endif

    #include:
    本质:将已经存在的文件内容,复制到当前文件中。(预编译中完成)

     1 // global.h
     2 int global = 10;
     3 
     4 // test.h
     5 #include <stdio.h>
     6 #include "global.h"
     7 
     8 const char* NAME = "Hello world!";
     9 
    10 void f()
    11 {
    12     printf("Hello world!
    ");
    13 }
    14 
    15 // test.c
    16 #include <stdio.h>
    17 #include "test.h"
    18 #include "global.h"
    19 
    20 int main()
    21 {
    22     f();
    23     
    24     printf("%s
    ", NAME);
    25     
    26     return 0;
    27 }

    编译test.c时,由于global.h同时在test.h中包含了,又在test.c中包含了,这样int global = 10;就在test.c中重复了两次,定义了两次,提示出错。

     1 // global.h
     2 #ifndef _GLOBAL_H_
     3 #define _GLOBAL_H_
     4 int global = 10;
     5 #endif
     6 
     7 // test.h
     8 #ifndef _TEST_H_
     9 #define _TEST_H_
    10 #include <stdio.h>
    11 #include "global.h"
    12 const char* NAME = "Hello world!";
    13 void f()
    14 {
    15     printf("Hello world!
    ");
    16 }
    17 #endif
    18 
    19 // test.c
    20 #include <stdio.h>
    21 #include "test.h"
    22 #include "global.h"
    23 
    24 int main()
    25 {
    26     f();  
    27     printf("%s
    ", NAME);  
    28     return 0;
    29 }

    使用条件编译,可以保证前面包含进来的(复制进来)内容,不再重复复制,而不管你写了多个头包含语句。

    #error和#line:

    #error用于生成一个编译错误信息,并停止编译

    #error message  //message不需要使用双引号包围,message是程序员自定义的信息

    #warring 用于生成警告,但不停止编译

     1 #include <stdio.h>
     2 #define CONST_NAME1 "CONST_NAME1"
     3 #define CONST_NAME2 "CONST_NAME2"
     4 int main()
     5 {  
     6     #ifndef COMMAND
     7     #warning Compilation will be stoped ...
     8     #error No defined Constant Symbol COMMAND
     9     #endif
    10     printf("%s
    ", COMMAND);
    11     printf("%s
    ", CONST_NAME1);
    12     printf("%s
    ", CONST_NAME2);
    13     return 0;
    14 }

    #line用于强制指定新的行号和编译文件名,并对源程序的代码重新编号
    本质:是重定义_LINE_和_FINE_(内部宏定义)

    用法:#line number filename

     1 #include <stdio.h>
     2 #line 14 "Hello.c"   //__LINE__=14,即下一行行号为14;__FILE__="Hello.c"
     3 #define CONST_NAME1 "CONST_NAME1"
     4 #define CONST_NAME2 "CONST_NAME2"
     5 void f()
     6 {
     7     return 0;  // 该行行号为20,提示出错
     8 }
     9 int main()
    10 {
    11     printf("%s
    ", CONST_NAME1);
    12     printf("%s
    ", CONST_NAME2);
    13     printf("%d
    ", __LINE__);  //27
    14     printf("%s
    ", __FILE__);  //hello.c  
    15     f();  
    16     return 0;
    17 }


    #pragma:

    #pragma是编译器指示字,用于指示编译器完成一些特定的动作;它所定义的很多指示字是编译器和操作系统特有的;在不同的编译器间不可移植。

    预处理器将忽略它不认识的#pragma指令

    两个不同的编译器可能以两种不同的方式解释同一条#pragma指令

    #pragma message

    #和##号运算符:

    #用于在预编译期将宏参数转换为字符串,注意:是在预编译期完成

     1 #include <stdio.h>
     2 #define CONVERS(x) #x  //#用于将CONVERS(x)中的x转换为x字符串
     3 int main()
     4 {   
     5     printf("%s
    ", CONVERS(Hello world!)); //Hello world!
     6     printf("%s
    ", CONVERS(100)); //100
     7     printf("%s
    ", CONVERS(while)); //while
     8     printf("%s
    ", CONVERS(return)); //return
     9     return 0;
    10 }
     1 #include <stdio.h>
     2 #define CALL(f, p) (printf("Call function %s
    ", #f), f(p))   
     3 int square(int n)
     4 {
     5     return n * n;
     6 }
     7 
     8 int f(int x)
     9 {
    10     return x;
    11 }
    12 
    13 int main()
    14 {
    15     printf("1. %d
    ", CALL(square, 4));
    16     // Call function square 
    17     //1.16
    18     printf("2. %d
    ", CALL(f, 10)); 
    19     //Call function f
    20     //2.10
    21     return 0;
    22 }

    ##用于在编译期粘连两个符号:

     1 #include <stdio.h>
     2 #define NAME(n) name##n
     3 int main()
     4 {   
     5     int NAME(1);
     6     int NAME(2); 
     7     NAME(1) = 1;
     8     NAME(2) = 2; 
     9     printf("%d
    ", NAME(1)); //1
    10     printf("%d
    ", NAME(2)); //2
    11     return 0;
    12 }
    内在的趣味,表面的繁琐
  • 相关阅读:
    SOA简介
    WebService传XML
    架构设计师与SOA(转)
    第二次自己总结WebService
    SQL SERVER的数据类型
    使用.ashx文件处理IHttpHandler实现发送文本及二进制数据的方法
    写了一个分页存储过程把总记录数也写到返回表的每行了
    ASP.net新手经常会碰到的问题
    动态添加、删除附件
    七问七答 SOA
  • 原文地址:https://www.cnblogs.com/data1213/p/4821896.html
Copyright © 2011-2022 走看看