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

【C语言】程序环境与预处理

目录

程序的翻译环境和执行环境

粗谈编译+链接

翻译环境

编译的几个阶段及链接

运行环境

预处理详解

预定义符号

#define

#define 定义标识符

#define 定义宏

#define 替换规则

#和## 

带副作用的宏参数

宏和函数的对比

命名约定

#undef

命令行定义

条件编译

文件包含

头文件被包含的方式


程序的翻译环境和执行环境

在ANSI C(标准C)的任何一种实现中,存在两个不同的环境。
第一种是翻译环境,在这个环境中源代码(.c 文件)被转换为可执行的机器指令(二进制指令,.exe文件)。

(VS->生成->生成解决方案)

  

 VS 是集成开发环境,在以上过程中,它充当了翻译环境。

第二种是执行环境,它用于实际执行代码。

计算机只能执行二进制指令

粗谈编译+链接

翻译环境


 

● 组成一个程序的每个源文件(.c) 都单独通过编译器分别转换成目标代码(object code , obj)。

● 每个目标文件由链接器 (linker) 捆绑在一起,形成一个单一而完整的可执行程序。

● 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

编译的几个阶段及链接

编译还可以分为三个阶段:预编译(预处理)、编译和汇编。

各个阶段的工作:

预处理阶段:进行 1、头文件的包含 (头文件在预处理阶段被展开,以后就不存在头文件了,即头文件不参与预处理以后的步骤。) 2、define 符号替换和删除 3、注释的删除 ,这些都是文本操作,最终生成 .i 文件。

编译阶段:(详见《编译原理》)分别对每个 .i 文件进行语法分析、词法分析、语义分析、符号汇总(符号汇总:记录全局变量名、自定义函数名和 main 函数名,如果这些函数有定义,会生成它们的地址,将符号和地址一一对应的表格,就叫符号表), 把代码翻译成汇编代码。生成 .s 文件

汇编阶段:把汇编代码翻译成二进制指令,生成目标文件(gcc 是 .o 文件,VS 是 .obj 文件),二进制指令存放在目标文件,并形成符号表(符号汇总时的符号和它们的地址所形成的表格)。

链接阶段:在这之前,每个源文件都是独立的,它们互不干扰,在链接阶段,它们就有一定的联系,这个阶段主要进行:1、合并段表 2、符号表的合并和重定位(每个目标文件都形成了一个符号表,这些符号表可能有一些符号的地址是无效的,比如 main 函数中 extern int Add(int x,int y),声明外部函数 Add ,Add 在 main 函数的源文件所生成的符号表的地址就是无效的(没有在mian函数定义),通过合并符号表将无效的地址重定位(比如 Add 函数在其他源文件找到定义,也就是说在其他源文件形成的符号表找到 Add 的函数地址),如果在链接阶段之后还是发现有无效地址(有函数找不到定义),就会报出“无法解析的外部符号”的错误)

运行环境

程序执行的过程:

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

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

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

(推荐阅读:《程序员的自我修养》)

预处理详解

预定义符号

__FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 _
http://www.cnnetsun.cn/news/1333033.html

相关文章:

  • SCUT_thesis项目:解决长章名换行后不居中的排版问题
  • PowerPlatformConnectors三大类型深度对比:自定义、认证与独立发布者连接器怎么选?
  • Pleaserun vs 手动编写init脚本:效率提升10倍的秘密
  • dbblog部署教程:Docker容器化部署与服务器配置全流程
  • AniVu BitTorrent下载功能深度测评:速度与稳定性全面测试
  • DC-TTS语音合成效果对比:LJ Speech与KSS数据集实测
  • 提升Haskell开发效率:ghcid高级功能与实用技巧
  • Saasify:让API变现从未如此简单!一站式实现API商业化的终极指南
  • Ikemen-GO开发者指南:用Go语言构建自定义格斗游戏引擎
  • GoMLX未来路线图:即将发布的5大令人期待的功能
  • lidar_camera_calib常见问题排查:从数据准备到结果验证的全流程避坑指南
  • 如何用tinygrad实现高效目标检测:YOLO和RetinaNet完整指南
  • 如何用tinygrad实现高效全局优化:从模拟退火到能量最小化的完整指南
  • 提升深度学习模型性能:tinygrad图像数据增强完全指南
  • 如何利用tinygrad数据流水线实现高效数据加载和预处理:从理论到实践
  • 为什么选择gorilla/csrf?深入解析Go语言中最受欢迎的CSRF防护库
  • 终极指南:Renovate如何通过智能机制实现实时安全更新防护
  • 如何使用bevy_ecs_tilemap创建你的第一个瓦片地图:从安装到运行的简单教程
  • Ragnar开发者指南:如何利用IPC API构建自定义窗口管理插件
  • 终极Docker镜像优化指南:使用Dive实现99%效率的完整教程
  • 从入门到精通:Android Emulator Runner多API级别与设备配置实践
  • 如何为Tailwind Next.js Starter Blog配置自动化测试:Jest与React Testing Library完整指南
  • 【开题答辩全过程】以 基于ssm校园教室设备检修管理系统为例,包含答辩的问题和答案
  • 如何高效处理fzf加载事件:从初始列表到高级配置的完整指南
  • 华为OD机试双机位C卷-不等式是否满足约束并输出最大差 (C/C++/Py/Java/Js/Go)
  • Java毕业设计基于springboot+Vue框架的学生交流互助平台16603185
  • 探索txtai项目:从语义搜索到LLM应用的完整指南
  • DebugView++高级功能揭秘:书签、时间戳与链路追踪技巧
  • 2024 AList 社区开发者大会与 Meetup 全攻略:不容错过的技术盛宴
  • 为什么Linkding选择Django作为后端框架?深入解析自托管书签管理器的技术选型