精华内容
下载资源
问答
  • c语言编译原理

    2015-03-29 13:46:58
    深入介绍c编译原理,深入掌握c必读文本,希望大家喜欢。
  • C语言编译原理

    2014-06-19 15:34:26
    C语言编译过程很有趣,从预处理,编译,汇编,链接,每一步都很重要,但是很少人关注这些。这是我自己总结的,希望能帮到大家!
  • c语言编译原理词法语法分析c语言编译原理词法语法分析
  • C语言编译原理课设词法分析C语言编译原理课设词法分析
  • 学下C语言编译原理: 名词概念: 编辑器:我们编写代码的窗口,有记事本,notepad++等 编译器:检查用户代码的一些语法错误兵将其编译成汇编代码 汇编器:将编译出来的文件变成目标代码 连接器:将目标代码连接成可...
    • 编译的完整过程,以下5步:

      C源程序-->预编译处理(.c)-->编译、优化程序(.s、.asm)-->汇编程序(.obj、.o、.a、.ko)-->链接程序(.exe、.elf、.axf等)。
      1.c源程序:IDE写好
      2.预编译处理(.c):替换宏定义指令,条件编译,头文件包含指令,
      3.编译、优化程序:检查经第二步处理过的文件语法错误以及将这些代码编译成汇编文件。
      4.汇编程序:将汇编代码翻译成目标二进制文件,在windows下是.obj;在linux下是o,.a,.ko等文件。
      5.链接程序:将被包含的头文件链接到一起, 第5步这里链接分为函数库静态链接库.lib和链接动态库.dll。静态库链接会在编译时被编译进汇编文件,而动态库则是在执行时需要才被链接。

    展开全文
  • C语言编译原理课程设计报告,详细认真的分析了各个算法与程序代码
  • 编译原理简单的词法分析器,c语言编写 词法分析器 C语言 编译原理 何炎祥 词法分析器实验
  • c语言 编译原理 分词

    2008-10-15 18:21:24
    c语言 编译原理 分词 定义Token表示右部的值。 检查语义错误: (标识符声明、定义和使用) 没有声明;重复声明;类型不相容 符号表 (标识符名,地址,类型) 过程:读入Token 遇到标识符声明时,检查是否已...
  • C语言编译原理介绍

    千次阅读 2014-04-02 20:46:01
    c语言编译原理图 1、预处理指令:gcc -E file.c -o hello.i # 删除所有的注释,以空格代替 # 将所有的#define删除,并且展开所有的宏定义 # 处理条件编译指令#if,#ifdef,#elif,#else,#endif  指令 用途  # ...

    c语言编译原理图


    1、预处理指令:gcc -E file.c -o hello.i

    # 删除所有的注释,以空格代替

    # 将所有的#define删除,并且展开所有的宏定义

    # 处理条件编译指令#if,#ifdef,#elif,#else,#endif

        指令         用途
        #           空指令,无任何效果
        #include    包含一个源代码文件
        #define     定义宏
        #undef      取消已定义的宏
        #if         如果给定条件为真,则编译下面代码
        #ifdef      如果宏已经定义,则编译下面代码
        #ifndef     如果宏没有定义,则编译下面代码
        #elif       如果前面的#if给定条件不为真,当前条件为真,则编译下面代码,其实就是else if的简写
        #endif      结束一个#if……#else条件编译块
        #error      停止编译并显示错误信息

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

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

    '#pragma'它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作

    2、编译指令:gcc -S file.c -o hello.S

    # 对预处理文件进行一系列词法分析,语法分析和语义分析

    词法分析主要分析关键字,标示符,立即数等是否合法

    语法分析主要分析表达式是否遵循语法规则

    语义分析在语法分析的基础上进一步分析表达式是否合法

    # 分析结束后进行代码优化生成相应的汇编代码文件

    3、汇编指令:gcc -c file.S -o hello.o

    # 汇编器将汇编代码转变为机器可以执行的指令

    每个汇编语句几乎都对应一条机器指令

    4、链接器的意义

    链接器的主要作用是把各个模块之间的相互引用的部分处理好,使得各个模块之间能够正确的衔接。

    链接分为静态链接和动态链接:静态链接指的是.o文件与链接库.a文件拼接在一起,组成可执行文件。这样编译出的可执行文件较大,也占用较大的内存空间,如果可执行程序,被并发运行多次,则会重复调用.a链接库文件进入内存。这样就造成了很大的浪费。静态链接是以空间换取时间。


    动态链接是指,链接库文件不是和.o文件拼接在一起,而是当执行文件运行时,才动态的去内存调用库文件,如果没有就动态的加载。动态链接是以时间换取空间。


    # 编译器将编译工作主要分为预处理,编译和汇编三部分

    # 链接器的作用是把各个独立的模块链接为可执行程序

    # 静态链接在编译期完成,动态链接在运行期完成

    一、宏定义与使用分析
    1、定义宏常量
    #define定义宏常量可以出现在代码的任何地方
    #define从本行开始,之后的代码都可以使用这个宏常量

    宏定义的常量或表达式没有作用域的限制。

    下面是示例代码:
    example2-1.c
    #include <stdio.h>

    int f1(int a, int b)
    {
        #define _MIN_(a,b) ((a)<(b) ? a : b) 
        return _MIN_(a, b);
        
        //#undef _MIN_//取消已经定义的宏,如何使用,就会报错,因为f2中找不到_MIN_
    }

    int f2(int a, int b, int c)
    {
        return _MIN_(_MIN_(a,b), c);
    }

    int main()
    {
        printf("%d\n", f1(2, 1));
        printf("%d\n", f2(5, 3, 2));
        
        return 0;
    }
    如下定义宏常量都正确:
    #define ERROR -1
    #define PI 3.1415926
    #define PATH_2 “D:\delphi\c\topic3.ppt”
    #define PATH_1 D:\delphi\c\topic3.ppt
    #define PATH_3 D:\delphi\c\                                                 // 续接符
    topic3.ppt
    因为宏常量在预处理阶段只是做简单的宏替换,所以不会出现错误。除非在编译阶段做语法检查时,可能会出现语法错误。
    2、定义宏表达式
    1、#define表达式给有函数调用的假象,却不是函数
    2、#define 表达式可以比函数更强大
    3、#define表达式比函数更容易出错
    #define sum(a,b) (a)+(b)
    #define min(a, b) ((a)<(b) ? (a) : (b))
    #define dim(a) (sizeof(a)/sizeof(*a))
    下面是代码演示:
    text.c
    #include <stdio.h>
    #define sum(a, b) ((a) + (b))  //如果不加上括号,容易出现错误
    #define min(a, b) ((a<b) ? (a) : (b))
    #define dim(array) (sizeof(array)/sizeof(*array))

    int main()
    {
    printf("%d\n", sum(1, 2) * sum(1, 2));
    printf("%d\n", min(3, 4));
        return 0;
    }
    3、宏代码块的定义:
    2-1.c
    #include <stdio.h>
    #include <malloc.h>

    #define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
    #define FOREVER() while(1)

    #define BEGIN {
    #define END   }
    #define FOREACH(i, m) for(i=0; i<m; i++)

    int main()
    {
        int array[] = {1, 2, 3, 4, 5};
        int x = 0;
        int*p = MALLOC(int, 5);
        
        FOREACH(x, 5)
        BEGIN
            p[x] = array[x];
        END
        
        FOREACH(x, 5)
        BEGIN
            printf("%d\n", p[x]);
        END
        
        FOREVER();
        
        free(p);
        
        printf("Last printf...\n");
        
        return 0;
    }
    很好的运行宏可以拓展C语言的关键字,但#define不能实现递归
    如果在程序出现错误,而没有报错行号的时候,就选择单步调试,来查找错误。
    预处理,只是做替换,所以不会理会语法是否错误。
    宏表达式与函数的对比
    # 宏表达式在预编译期被处理,编译器不知道宏表达式的存在
    #宏表达式用“实参”完全替代形参,不进行任何运算
    # 宏表达式没有任何的“调用”开销
    #宏表达式中不能出现递归定义
    #define fac(n) ((n>0) ? (fac(n-1)+1) : 0)
    int j = fac(100);   //这里的递归是无法实现的,原因就是宏只是做简单的替换。
    强大的内置宏:

    代码示例:教你定义日志宏
    #include <stdio.h>
    #include <time.h>

    #define LOG(s) do{                \
            time_t t;                        \
    struct tm* ti;               \
    time(&t);                     \
    ti = localtime(&t);            \
    printf("%s", asctime(ti));  \
    printf(s);                             \
    }while(0)
    

    int main()
    {
    LOG("Enter main()...\n");

    LOG("Exit main()...\n");

    return 0;
    }
    课后思考:
    #define f (x) ((x)-1)
    1、上面的宏定义代表什么意思?
    f   ==  (x) ((x)-1)

    2、宏定义对空格敏感吗?宏“调用”对空格敏感吗?

    敏感,敏感。

    二、条件编译使用分析

    1、基本概念

    # 条件编译的行为类似于C语言中的if...else

    # 条件编译是预编译指示命令,用于控制是否编译某段代码

    #define C 1

    int main()

    {

    #if ( C == 1 )

    printf("this is first printf...\n");

    #else

    printf("this is second printf...\n");

    #endif

    return 0;

    }

    条件编译与if语句的区别就是,虽然结果相同,但中间结果不同。

    在编译时可以使用宏定义行命令来定义宏:gcc -DC=1 test.c -o test

    if语句是根据条件表达式,分开来执行某行代码。而条件编译时告诉编译器要处理哪块,不处理哪块,而if语句都要编译。

    2、#include的困惑

    2.1#include的本质是将已经存在的文件内容嵌入到当前文件中

    2.1#include的间接包含同样会产生嵌入文件内容的动作,如何来解决这样的问题,下面就用条件编译来解决此问题

    // global.h
    #ifndef _GLOBAL_H_   //使用条件编译避免了global.h的重复嵌入

    #define _GLOBAL_H_

    int global = 10;
    #endif
    // test.h
    #ifndef _TEST_H_
    #define _TEST_H_
    #include <stdio.h>
    #include "global.h"  //由于使用了条件编译,所以这里不会重复嵌入
    const char* NAME = "Hello world!";
    void f()
    {
        printf("Hello world!\n");
    }
    #endif
    // test.c
    #include <stdio.h>
    #include "test.h" 
    #include "global.h"
    int main()
    {
        f();   
        printf("%s\n", NAME);  
        return 0;
    }

    3.条件编译的意义

    3.1、条件编译使得我们可以按不同的条件编译不同的代码段,因而可以产生不同的目标代码

    3.2、#if...#else...#endif被预编译器处理;而if...else语句被编译器处理,必然被编译进目标代码

    3.3、实际工程中条件编译主要用于两种情况:

    # 不同的产品线共用一份代码

    # 区分编译产品的调试版和发布版

    产品线区分及条件编译应用:

    #include <stdio.h>
    #ifdef DEBUG
        #define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s)
    #else
        #define LOG(s) NULL
    #endif
    #ifdef HIGH
    void f()
    {
        printf("This is the high level product!\n");
    }
    #else
    void f()
    {
    }
    #endif
    int main()
    {
        LOG("Enter main() ..."); 
        f();   
        printf("1. Query Information.\n");
        printf("2. Record Information.\n");
        printf("3. Delete Information.\n");
        #ifdef HIGH
        printf("4. High Level Query.\n");
        printf("5. Mannul Service.\n");
        printf("6. Exit.\n");
        #else
        printf("4. Exit.\n");
        #endif
        LOG("Exit main() ...");
        return 0;
    }

    以上代码可以实现一份代码变为两个不同的产品线(利用宏技术)。

    宏命令行的使用技巧:

    gcc -DDEBUG -DHIGH test.c

    通过宏可以使代码变得更有魅力。

    4、小结

    1、通过编译器命令行能够定义预处理器使用的宏

    2、条件编译可以避免重复包含同一个头文件

    3、条件编译是在工程开发中可以区别不同产品线的代码

    4、条件编译可以定义产品的发布版和调试版

    三、#error和#line

    1、#error的用法

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

    #error message

    注:message不需要用双引号包围

    #error编译器指示字用于自定义程序员特有的编译错误信息

    类似的,#warning用于生成编译警告,但不会停止编译

    代码示例:#error和#warning的使用,自定义错误信息

    #include <stdio.h>

    #define CONST_NAME1 "CONST_NAME1"
    #define CONST_NAME2 "CONST_NAME2"

    int main()
    {  
        #ifndef COMMAND
        #warning Compilation will be stoped ...    //自定义的错误报告
        #error No defined Constant Symbol COMMAND
        #endif

        printf("%s\n", COMMAND);
        printf("%s\n", CONST_NAME1);
        printf("%s\n", CONST_NAME2);

        return 0;
    }

    2、#line的用法

    2.1、#line用于强制指定新的行号和编译文件名,并对源程序的代码重新编号

    #line number filename //可以理解为对__LINE__和__FILE__的重定义

    注:filename可省略

    #line编译指示字的本质是重定义__LINE__和__FILE__(下划线为两个)

    代码示例:

    #include <stdio.h>

    //用于标示自己写的代码;
    //这一行向后,变为14行。文件名变为Hello.c
    #line 14 "Hello.c" 

    #define CONST_NAME1 "CONST_NAME1"
    #define CONST_NAME2 "CONST_NAME2"

    void f()
    {
        return 0;
    }

    int main()
    {
        printf("%s\n", CONST_NAME1);
        printf("%s\n", CONST_NAME2);
        printf("%d\n", __LINE__);
        printf("%s\n", __FILE__);
        
        f();

        return 0;
    }

    四、#pragma预处理分析

    1、#pragma简介

    #pragma是编译器指示字,用于指示编译器完成一些特定的动作

    #pragma所定义的很多指示字是编译器和操作系统特有的

    #pragma在不同的编译器间是不可移植的

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

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

    一般的用法: #pragma parameter

    注:不同的parameter参数语法和意义各不相同

    #pragma message

    1、message参数在大多数的编译器中都有相似的实现

    2、message参数在编译时输出消息到编译输出窗口中

    3、message可用于代码的版本控制

    注意message是VC特有的编译指示符,GCC中将其忽略

    实例代码:

    #include <stdio.h>

    #if defined(ANDROID20)
        #pragma message("Compile Android SDK 2.0...")
        #define VERSION "Android 2.0"
    #elif defined(ANDROID23)
        #pragma message("Compile Android SDK 2.3...")
        #define VERSION "Android 2.3"
    #elif defined(ANDROID40)
        #pragma message("Compile Android SDK 4.0...")
        #define VERSION "Android 4.0"
    #else
        #error Compile Version is not provided!
    #endif

    int main()
    {
        printf("%s\n", VERSION);

        return 0;
    }

    C语言中一个非常重要,但有容易让人忽略的知识点:#pragma pack

    1、什么是内存对齐

    不同类型的数据在内存中按照一定的规则排列;而不是顺序的一个接一个的排放的,这就是对齐

    2、为什么需要内存对齐?

    2.1、CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1、2、4、8、16字节

    2.2、当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣。也就是说,字节对齐一定程度上提高了效率。

    2.3、某些硬件平台只能从规定的地址处取某些特定类型的数据,否则抛出硬件异常

    实例代码:

    #include <stdio.h>
    
    #pragma pack(8)
    
    struct S1
    {
        short a;    
        long b;
    };
    成员对齐数	要求对齐字节	结构体成员	起始地址	大小	空字节数
    2		8		short a		0		2	0
    4		8		long b		4		4	2
    struct S2
    {
        char c;
        struct S1 d;
        double e;
    };
    成员对齐数	要求对齐字节	结构体成员	起始地址	大小	空字节数
    1		8		char c		0		1	0
    4(成员最大)<span style="white-space:pre">	</span>8		struct s1 d	4		8	3
    8		8		double e	16		8	4
    
    
    #pragma pack()
    
    int main()
    {
        struct S2 s2;
        
        printf("%d\n", sizeof(struct S1));
        printf("%d\n", sizeof(struct S2));
        printf("%d\n", (int)&(s2.d) - (int)&(s2.c));
    
        return 0;
    }
    

    3、struct占用的内存大小

    3.1、第一个成员起始于0偏移处

    3.2、每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐

    3.2.1、偏移地址和成员占用大小均需对齐

    3.2.2、结构体成员的对齐参数为其所有成员使用的对齐参数的最大值

    3.3、结构体总长度必须为所有对齐参数的整数倍

    课后问题:

    结构体变量是否可以直接用memcmp函数进行相等判断?为什么?

    答:不可以。因为结构体相等是指,其含有相同的成员变量。而由于对齐方式不同,会导致成员在内存中的位置发生变化。而这就不可以使用memcmp函数通过内存空间数据来判断结构体是否相等。

    五、#和##号

    1、#运算符

    #运算符用于在预编译期将宏参数转换为字符串

    #include <stdio.h>
    
    #define CONVERS(x) #x
    
    int main()
    {
        
        printf("%s\n", CONVERS(Hello world!));
        printf("%s\n", CONVERS(100));
        printf("%s\n", CONVERS(while));
        printf("%s\n", CONVERS(return));
    
        return 0;
    }
    
    运行结果:

    Hello world!

    100

    while

    return

    #运算符在宏中的妙用

    #include <stdio.h>
    
    #define CALL(f, p) (printf("Call function %s\n", #f), f(p)) //#只能在宏中使用
       
    int square(int n)<pre code_snippet_id="275014" snippet_file_name="blog_20140404_4_4836671" name="code" class="cpp">#include <stdio.h>
    
    #define NAME(n) name##n
    
    int main()
    {
        
        int NAME(1);
        int NAME(2);
        
        NAME(1) = 1;
        NAME(2) = 2;
        
        printf("%d\n", NAME(1));
        printf("%d\n", NAME(2));
    
        return 0;
    }
    

    { return n * n;}int f(int x){ return x;}int main(){ printf("1. %d\n", CALL(square, 4));
    
    
    //调用sequare函数 printf("2. %d\n", CALL(f, 10)); //调用f函数 return 0;}

    
    2、##运算符用于在预编译期粘连两个符号
    

    #include <stdio.h>
    
    #define NAME(n) name##n
    
    int main()
    {
        
        int NAME(1);
        int NAME(2);
        
        NAME(1) = 1;
        NAME(2) = 2;
        
        printf("%d\n", NAME(1));
        printf("%d\n", NAME(2));
    
        return 0;
    }
    

    /*高通使用的代码*/

    #include <stdio.h>
    #define STRUCT(type) typedef struct _tag_##type type;\
    struct _tag_##type

    STRUCT(Student)
    {
        char* name;
        int id;
    };

    /*
    typedef struct _tag_student student;\
    struct _tag_student
    {
        char* name;
        int id;
    }
    */

    int main()
    {
        
        Student s1;
        Student s2;
        
        s1.name = "s1";
        s1.id = 0;
        
        s2.name = "s2";
        s2.id = 1;
        
        printf("%s\n", s1.name);
        printf("%d\n", s1.id);
        printf("%s\n", s2.name);
        printf("%d\n", s2.id);

        return 0;
    }

    
    
    展开全文
  • C语言编译原理001,很重要,找了很久,终于找到了
  • 这个是编译原理的语法分析器,自己做的,完全能运行成功,是在DEV C++上运行的,用C语言写的 输出结果是follow集 first集,预测分析表,待分析的输入串是否符合语法规则。诚心诚意,绝不是标题党。
  • C语言编译原理 很重要,很详细,找了好久。 终于找到了
  • 预处理:c语言主要有两种文件 .c 和 .h 文件,#include和#define都是预处理,主要包括宏定义 文件包含 条件编译(eg:用于中英文版本使用一套源码的情况跟if else的区别就是可以是代码的精简if else中的两部分代码...

    预处理:c语言主要有两种文件 .c 和 .h 文件,#include和#define都是预处理,主要包括宏定义 文件包含 条件编译(eg:用于中英文版本使用一套源码的情况跟if else的区别就是可以是代码的精简if else中的两部分代码都会进行编译,而条件编译是不符合条件就不会进行编译)三种,编译器看见的文件都是预处理之后的样子。比如进行过宏定义之后,预处理就是将宏进行替换然后给编译器进行识别,头文件还可以插入到源代码中。

    编译:对象是单个的头文件和其中递归包含的头文件组成的编译单元。一般来说头文件不直接参与编译。c语言编译的时候在windows系统下将生成  .obj 文件,在unix系统中将生成 .o文件

    同时会进行语法的检查,词法分析,产生目标代码并进行优化,为全局变量和局部变量分配内存,并检查函数是否定义,如果没有定义会检查函数是否声明,若有函数声明则就告诉编译器函数的定义将晚些定义或者在其他文件中进行定义,你先给我编译通过。

    链接:是将编译生成的零散的二进制机器代码组合成可以执行的文件,一是解析其他文件中的函数引用或其他引用,二是解析库函数。

    函数必须先声明再引用,如果不定义函数的话 能编译但是不能进行链接,连接错误的原因就是不能找到函数实体。

    原因举例:例如1.c文件中声明并且调用了一个函数,这个函数却在2.c中进行的定义,链接就是在2.c中找到函数并对其进行解析,若是找不到就会进行错误提示:存在尚未解析的对象,声明的外部变量也是这样。

    展开全文
  • 只是附录c.1的词法分析器,但是直接用codeblocks打开就可以直接运行了,测试过没有错误的
  • 设计并实现一个C语言词法分析程序(1)可以识别出用C语言编写的源程序中的每个单词符号,以记号的形式输出每个单词符号。 (2)可以识别并跳过源程序中的注释。 (3)可以统计源程序中的语句行数、各类单词的个数、以及字符...
  • C语言词法分析程序,输出结果是二元关系,编译原理实验题目。
  • C语言编译原理简介

    千次阅读 2012-06-17 14:17:59
    2. 编译器: 检查用户代码的一些语法错误并且将其编译成汇编代码。 3.汇编器:将编译出来的文件变成目标代码(windows 下的.obj文件) 4.连接器:将目标代码连接成为可执行文件(.exe),及双击就可以运行文件。 ...

    1. 编辑器: 我们编写代码的一些窗口,如:记事本、word、notepad等。

    2. 编译器: 检查用户代码的一些语法错误并且将其编译成汇编代码。

    3.汇编器:将编译出来的文件变成目标代码(windows 下的.obj文件)

    4.连接器:将目标代码连接成为可执行文件(.exe),及双击就可以运行文件。

    5.集成开发环境(Integrated Development Environment, 简称IDE):是用于程序开发环境的应用程序。一般包括代码编辑器、编译器、调试器和图形用户界面工具。如:VC6.0、C_Free等。

                                                                                                           其他目标代码-》

                   (.c  .cpp)源代码-》编译器-》(.s)汇编代码-》汇编器-》(.o)目标代码-》链接器-》可执行程序

                                                                                                                    库文件-》

     

     

    编译的完整过程:

          C源程序-》 预编译处理(.c)-》编译、优化程序(.s   .asm)->汇编程序(.obj、 .o、.a、 .ko)-->链接程序(.exe、 .elf、 .axf 等)

    1. C源程序

           自己编写的程序代码

    2. 预编译处理(.c)

       包括四个过程

       a. 宏定义指令, 如#define N 6,    #undef 等

           对于前一个伪指令,预编译所要做的是将程序中的所有N用6替换,请大家注意这里是替换、并不是像作为函数那样将6复制进N这个变量。对于后者,则将取消对某个宏的定义,使以后出现的N不再被替换。

      b.条件编译指令,如#ifdef,  #ifndef,  #endif 等。

          这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。这样就能在编译阶段减少编译时间,提高效率,看看这是多好的指令。

    c. 头文件包含指令,如#include "file.h" 或#include <file.h>等

         在头文件中一般用伪指令#define 定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。

        采用这样的做法一来可以让我们直接调用一些复杂库函数;二来可以免去我们在写程序时重复做一些定义声明工作的麻烦。试想一下,一旦我们写好头文件,那么以后要用到相关模块就再也不用写这些函数了, 直接#include 就OK了,这可是一劳永逸啊。

     

     #include<>  告诉编译器去系统默认的路径寻找相关的文件。

    #include"":    告诉编译器先去源程序所在目录下寻找,如果没有就去系统默认路径寻找。

    d.  特殊符号,预编译程序可以识别一些特殊的符号。

     例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序就是对在源程序中出现的这些特殊符号将用合适的值进行替换。

          大家注意到没,预编译阶段基本上是完成对源程序的相关代码进行替换,这样之后程序的原意没有改变,就是代码的内容有所不同,这样为以后的编译做好准备。

    3. 编译、优化程序(.s、  .asm)

           经过上一阶段的处理,现在我们的程序已经没有宏定义,包含头文件等指令了,只剩下一些变量、常量、关键字等,而编译的主要作用是检查这些代码的语法错误及将这些代码编译成为汇编文件。

     

    4. 汇编程序(.obj、   .o、  .a、  .ko)

      在这个阶段是将汇编代码翻译成目标文件,这时的文件已经是二进制代码了。在windows环境下文件的后缀名是.obj;   在unix下则有是o、  .a、 .ko 等文件。

      目标文件由段组成。通常一个目标文件中至少有两个段:

       代码段:  该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。

       数据段: 主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

     

    5.  链接程序(.exe、  .elf、   .axf)

      被包含的头文件,以及当我们的程序分布于很多源文件时,那么这些源文件该怎么处理呢,这就是连接器的作用,它们被翻译成目标代码后需要被链接到一起才能被执行。

       谈到函数库的链接,我们还需要了解点函数库的知识,函数库分静态链接库(又称静态库*.lib) 和链接动作库(又称动态库 *.dll)

       静态库的链接在编译时会被编译进汇编文件,这样的操作会改变文件大小;而动态库则是在执行时(双击运行),当需要动态库中的文件时,才被链接到可执行文件的。

     

     

     

     

    展开全文
  • c语言编译原理及IPC通信经典面试题

    千次阅读 2017-08-03 21:52:28
    C语言编译大致过程:预处理 -->编译 -->汇编 --> 可执行文件   具体过程:预处理 -->编译优化 -->汇编 -->链接过程 --> 可执行文件   格式变化:.c -->.i -->.s -->.o -->可执行文件 19.udp如何确认被...
  • 在编写自己的c语言代码之前,有必要了解c语言代码是如何被编译系统编译的 1. 编辑器: 我们编写代码的一些窗口,如:记事本、word、notepad等。 2. 编译器: 检查用户代码的一些语法错误并且将其编译成...
  • C语言代码的编译原理: http://blog.csdn.net/neil_wesley/article/details/51265457 Java语言的编译原理: http://www.cnblogs.com/wade-luffy/p/5925728.html Java语言平台版本: (1)J2SE(Java 2 ...
  • 宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译
  • C语言数组编译原理

    2020-08-03 13:52:17
    关于C语言数组编译原理的讨论。
  • 这里给大家推荐的是一些c语言编译供大家学习参考,希望这些c语言编译能够有效地帮助到大家学习c语言。具体的推荐如下:本书是由c语言的设计者brian w. kernighan和dennis m. ritchie编写的一部介绍标准c语言及其程序...
  • C语言编译原理——

    2020-09-25 10:50:55
    C语言编译原理——
  • 编译原理(九)C语言编译系统

    千次阅读 2018-02-02 19:41:56
    C语言编译系统: 两边扫描,有些跳转代码,要等翻译过后,才能知道具体位置,所以要进行第二遍编译: 连接器 目标模块或目标文件的形式 可重定位的目标文件可执行的目标文件共享目标文件----一种特殊...
  • C语言编译的基本原理

    2018-01-25 16:23:30
    C语言编译的基本策略是使用程序将源代码文件转换为可执行文件。 这个过程分为三部分: 源代码文件 ------> 目标代码文件------>可执行文件 用到两个组件: 编译器、链接器。 编译器的作用是将源代码转换为中间...
  • 编译原理 词法分析器 C语言 编译原理 词法分析器 C语言
  • 前几天有个朋友问我关于C语言编译原理和编译的过程,当时我也没有说明白,今天特意在书上和网上查阅资料,简单的总结了一下关于C语言编译原理及过程。集成开发环境是用于提供程序开发环境的应用程序,一般包括...
  • C语言编译原理及过程

    万次阅读 2016-07-13 10:08:21
    前几天有个朋友问我关于C语言编译原理和编译的过程,当时我也没有说明白,今天特意在书上和网上查阅资料,简单的总结了一下关于C语言编译原理及过程。  集成开发环境是用于提供程序开发环境的应用程序,一般...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 76,850
精华内容 30,740
关键字:

c语言编译原理

c语言 订阅