当前位置: 首页 > news >正文

【C语言进阶】程序环境和预处理

目录

1.翻译环境

1.2 预编译

1.3 编译

1.4 汇编

1.5 链接 

2.运行环境

3. 预处理详解

3.1 预定义符号

3.2 define定义标识符

3.3 #define定义宏 


1.翻译环境

        所谓翻译环境,就是在这个环境中源代码被翻译成可执行的机器指令。

        多个源文件经过编译器生成各自目标文件,最后这些目标文件需要链接器进行链接生成一个可执行程序。

1.2 预编译

编译分为三个阶段:预编译、编译、汇编。

 为了能更好地演示,这里使用linux中的gcc编译器来展示。

①首先我们编写好一段代码,使用gcc test.c -E -o test.i对源文件进行预编译,输出内容放到test.i中;我们发现预编译之后生成的文件中,除了本身的源码还掺杂了一堆其他的东西。

普通的代码:

#include<stdio.h>// 全局变量
int gval = 2025;
int Add()
{return x + y;
}
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,10};int i = 0;for(i = 0; i < 10;i++){printf("%d\n",arr[i]);}return 0;
}

预编译之后的结果:

 

 

②因为源文件只包含了stdio.h,那么我们就去头文件中寻找,结果发现两者有相同之处;所以我们断定在预处理/预编译阶段就会把头文件全部包含在源码之中。

③增加代码中规定注释和宏定义,再次进行预编译; 

#include<stdio.h>// 全局变量
int gval = 2025;
#define MAX 100
int Add()
{return x + y;
}// 一个平平无奇的注释
int main()
{int m = MAX;int arr[] = {1,2,3,4,5,6,7,8,9,10};int i = 0;for(i = 0; i < 10;i++){printf("%d\n",arr[i]);}return 0;
}

观察预编译结果:宏定义已经直接替换,注释也不见了

总结: 在预处理阶段,做的都是一些文本操作。

1.3 编译

       ① 使用gcc test.i -S 对预编译文件进行编译或者直接对源文件进行编译

上面的代码故意留了一个小问题,此时编译的时候报错,那么我们可以总结编译作用的第一条:根据语法语义对代码进行分析

②打开编译之后生成的代码,发现已经将源码转换成了汇编代码。这里的转换其中包含词法分析、语法分析、符号汇总(全局变量汇总)、语义分析

1.4 汇编

①使用gcc test.s -c 对代码进行汇编,生成目标文件。打开目标文件发现是二进制文件,如果正常使用文本编辑器是乱码。

②所以汇编可以将汇编代码转换成二进制指令

③ 此时会生成符号表,类似于将地址与全局函数进行关联绑定。符号表在链接阶段会使用到。

1.5 链接 

①合并段表;

数据的存储需要按照某种格式,那么linux是按照elf格式进行分段存储的,这里需要把相同的数据段进行合并,未来只需要对这个合并的文件进行链接即可。

②符号表的合并和重定位。

在汇编期间生成了多个符号表,有的符号表没有意义(类似于声明函数,其实没有分配空间),那么这种符号表就会进行合并,选择有效的地址进符号表。符号表的存在使得多个文件能够进行关联。   

2.运行环境

  程序执行过程:

①程序载入内存中,在有操作系统的环境中,由操作系统完成,若在独立环境中,程序的载入需要手动安排(烧录嵌入式板子),也可以通过可执行代码置入只读内存来完成。

②程序的执行开始调用main函数。

③程序使用运行时堆栈(stack),存储函数的局部变量和返回地址,程序同时可以使用静态内存,存储在静态内存的值在程序运行过程中始终保留值。

④终止程序,正常终止main函数;也可能是意外终止。

3. 预处理详解

3.1 预定义符号

这些符号可以直接使用,C语言原生自带。

 简单进行使用:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() 
{printf("file:%s line=%d date:%s time:%s ",__FILE__,__LINE__,__DATE__,__TIME__);return 0;
}

输出结果:

这些 预定义符号可以用于日志的记录:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() 
{FILE* ps = fopen("log.txt","w");if (ps == NULL){perror("fopen");return 1;}fprintf(ps,"file:%s line=%d date:%s time:%s ",__FILE__,__LINE__,__DATE__,__TIME__);fclose(ps);ps = NULL;return 0;
}

3.2 define定义标识符

语法:

        #define name stuff 

        几乎所有基本类型都可以使用define定义,需要注意的是,不要在define定义最后加分号 ,这样会引起很多不必要的误会。

#include<stdio.h>
#define MAX 1000
#define STR "hello"
#define print printf("hehe\n")int main()
{int m = MAX;print;printf("%s\n",STR);return 0;
}

3.3 #define定义宏 

        待续......

http://www.xdnf.cn/news/1192411.html

相关文章:

  • 各种前端框架界面
  • HighlightingSystem
  • 精密全波整流电路(四)
  • Linux 如何统计系统上各个用户登录(或者登出)记录出现的次数?
  • python 检测蜂窝网络,实现掉网自动拨号
  • 自定义定时任务功能详解
  • SGLang 核心技术详解
  • GO 从入门到精通2
  • TCP如何解决网络切换问题
  • 简单实现支付密码的页面及输入效果
  • @PathVariable与@RequestParam的区别
  • Zama+OpenZeppelin:将机密智能合约带入 DeFi 和数字资产领域
  • 拒绝SQL恐惧:用Python+pyqt打造任意Excel数据库查询系统
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 热词数量分析日期统计功能实现
  • 【数据结构】二叉树初阶详解(二):实现逻辑与代码拆解(超详版)
  • STL——vector
  • [Linux入门] 初学者入门:Linux DNS 域名解析服务详解
  • React入门学习——指北指南(第四节)
  • 雨雪雾冰全预警:交通气象站为出行安全筑起“隐形防护网”
  • 零基础学后端-PHP语言(第二期-PHP基础语法)(通过php内置服务器运行php文件)
  • 力扣112. 路径总和
  • GIS地理信息系统建设:高精度3D建模
  • 【愚公系列】《MIoT.VC》003-构建基本仿真工作站(组件的属性、行为、视频展示)
  • 基于匿名管道的多进程任务池实现与FD泄漏解决方案
  • 智慧水库管理平台数据清洗实施方案
  • C++对象模型
  • linux练习题
  • linux内核电源管理
  • JavaWeb(苍穹外卖)--学习笔记11(Filter(过滤器) 和 Interceptor(拦截器))
  • JavaScript中.splice()的用法