程序环境和预处理

发布于:2024-10-08 ⋅ 阅读:(159) ⋅ 点赞:(0)

翻译环境,在这个环境中源代码被转换为可执行的机器指令

执行环境,它用于实际执行代码

翻译环境

翻译环境分为编译与链接,是将我们编译的代码转换成程序运行的二进制代码进行转换。下面是讲述翻译环境: 

  • 组成一个程序的每个源文件通过编译过程分别转换成目标代码(.obj)。
  • 每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序(.exe)。
  • 【链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人 的程序库】链接库,将其需要的函数也链接到程序中。

编译 

编译分为预编译(预处理)、编译、汇编,下面讲这些程序的作用:

         预编译(预处理)

预编译是将头文件包含、宏定义的替换和删除、 注释删除等文本操作,是将.c文件进行预处理后变成.i文件。

          编译

 将C语言代码经过语法分析、词法分析、语义分析、符号汇总翻译成汇编代码,生成.s文件。

          汇编

将汇编代码翻译成二进制代码,在VS下生成的是.obj文件,在vscode-gcc环境下生成的是.o文件(目标文件)。

链接

所有的文件合并成一个可执行文件(.exe)。

运行环境

1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。

2. 程序的执行便开始。接着便调用main函数。

3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。

4. 终止程序。正常终止main函数;也有可能是意外终止。

------------预处理 

1.预定义符号

 2.#define

                2.1#define定义标识符       (所有的定义都不需要加;)

#define MAX 1000【将函数中的MAX替换成1000】

#define reg register  【为 register这个关键字,创建一个简短的名字】      

#define do_forever for(;;)    【将do_forever替换成for(;;)死循环】

#define CASE break;case  【将CASE替换成break;case,所以第一个case还是小写】

                 2.2#define定义宏

#define SQUARE( x ) x * x  【SQUARE( 5 ); -->  5*5;】

                                            【int a = 5; printf("%d\n" ,SQUARE( a + 1) );--> a+1*a+1;】

 所以定义宏时不要吝啬括号

                  2.3#define替换规则

                  2.4#和##         (只能在宏中定义)

int i = 10;

#define PRINT(FORMAT, VALUE) printf("the value of " #VALUE "is "FORMAT "\n", VALUE)

【PRINT("%d", i+3);-->  the value of i+3 is 13\n

代码中的 #VALUE 会预处理器处理为:"VALUE"

 #define SUM(x, y) x##y

【 SUM(L, X) = 100;-->   printf("%d\n", SUM(L, X));】  

                 2.5带副作用的宏参数

z = (x++)  >  (y++)  ?  (x++)  :  (y++); //首先需要判断两个数的大小所以需要先使用值再++,得到x=6,y=9.然后就是执行后面的语句为假y++ ,同样也是先使用值,所以z=9,原本y的值是9,再++则y=10,x不变x=6。

宏和函数对比

  • 宏比函数在程序的规模和速度方面更胜一筹;
  • 函数需要定义类型,宏不需要;
  • 使用宏会让原本长的代码加长;
  • 函数可以,宏不能调试;
  • 宏可能带来运算符优先级的问题,所以要括号;
  • 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不一样的结果;
  • 宏不能递归,函数可以;

                  2.6命名约定:一般宏全大写,函数首字母大写或驼峰表示法; 

 3.#undef

 4.命令行定义

某个程序中声明了一个某个长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大,我们需要一个数组能够大一些。

5.条件编译

          常见的条件编译指令

(1.

(2.多分支条件编译

 

(3. 是否被定义

(4.嵌套指令 

 5.文件包含

库文件是放在标准库里面的, 虽然库文件也可以使用“”进行包含, 但是这样效率就会变低,而且这样不容易区分本地文件和库文件了。

  •  #pragma once       //当一个项目中文件数过多, 可能出现头文件重复包含的情况。
  • 或者在头文件中这样写,也是只包含一次。


网站公告

今日签到

点亮在社区的每一天
去签到