C语言——可执行程序过程

简介: C语言——可执行程序过程
  • 我们在编写代码的时候,不知道大家是否和一开始的我一样,在运行代码的时候就直接CTRL+F5运行了呢??一开始,我只知道会生成一个.exe的可执行文件,中间的原理我一点也不知道。
  • 今天就由我带领大家对生成可执行的文件有更深的一层理解。
  • 程序的翻译环境和执行环境
  • 在ANSI C的任何一种实现中,存在两个不同的环境。
  • 第一种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。第二种是执行环境它用于 实际执行代码。
  • 组成一个程序的每个源文件通过编译过程分别转换目标代码。
  • 每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。
  • 链接器同时也会引入标准C库函数中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数链接到程序中。

翻译也分为几种过程:

  • 在预处理中,我们可以通过在Linux环境下,用gcc text.c -E -o text.i 来看一看在预处理中编译器做了什么
  • 我们发现短短10行的代码变成了700多行,这是因为在预处理中,包含的头文件被展开了,而且宏已经被替换了。
  • 在这里,大家有没有想过一个问题呢??在预处理阶段中,到底是宏替换先执行还是去注释先执行呢???

经过证明,我们发现去注释是先执行的,如果是宏替换先执行的话,那么就不会有Hello World的输出了。


预定义的符号:

  • _FILE_  //进行编译的源文件
  • _LINE_ //文件当前的行号
  • _DATE_ //文件被编译的日期
  • _TIME_ //文件被编译的时间
  • _STDC_ //如果编译器遵循ANSI C ,其值为1,否则为定义

关于宏的定义,其实本质上就是在预处理的阶段被替换。


我们来看这个代码就知道了,我们用宏定义了SQUARE ,如果没有我刚刚说宏的本质是替换是不是很多人会以为答案是36,经过我上面说的,宏的本质是替换,所以就替换成了printf("%d\n",5+1&1+5);这个,答案就是11  

#define SQUARE(x)  x*x
int main()
{
  int a = 5;
  printf("%d\n", SQUARE(5 + 1));
  return 0;
}


宏的好处:

  • 在用于函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间多,所以宏比函数在程序上的规模和速度上更胜一筹。
  • 第二个就是宏是无关类型的

宏的坏处:

  • 宏不能递归,也不好调试
  • 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能产生不可预料的问题

  • 综上所述,其实我更推荐用函数,函数可以调试,而且在C++中用inline也综合了宏和函数的优缺点。

命名约定

宏名全部大写 函数名不要全部大写

命令行定义

在许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。 例如:当我们根据同一个源文件要 编译出不同的一个程序的不同版本的时候,这个特性有点用处。(假定某个程序中声明了一个某个长度的数组,如果 机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大写,我们需要一个数组能够大写。)

  • 比如,下面代码我就用到了命令行定义

常见的预处理指令

  • #ifndef
  • #define
  • #if
  • #endif
  • #elif
  • ...
  • 当然还有很多预处理指令,这里就不再叙述了。
  • 这里预处理指令中,我们常见的就是
  • #ifndef include <stdio.h>
  • #define include <stdio.h>
  • #endif
  • 这里是为了不让头文件重复包含,在我们的第一个图中就讲到了,在预处理中头文件会被展开,所以开text.i文件中会有700多行的代码
  • 当然#pragma once也可以防止头文件被重复包含


  • 最后:讲一讲大家在做大型项目中,头文件和定义总是分开的,都会用到#include "text.h"  或#include <filename.h>,我来讲一讲它们之间的差别。
  • 其实它们只是查找策略的不同,#include "filename.h"查找的策略是现在源文件所在的目录下查找,如果找不到编译器就会查找库函数头文件一样在标准位置查找头文件。如果找不到就提示编译错误
  • 而#include <filename.h> 是直接查找库函数头文件中的标准位置中查找头文件


相关文章
|
1月前
|
存储 自然语言处理 编译器
【C语言】编译与链接:深入理解程序构建过程
【C语言】编译与链接:深入理解程序构建过程
|
3月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
101 1
|
3月前
|
NoSQL 编译器 程序员
【C语言】揭秘GCC:从平凡到卓越的编译艺术,一场代码与效率的激情碰撞,探索那些不为人知的秘密武器,让你的程序瞬间提速百倍!
【8月更文挑战第20天】GCC,GNU Compiler Collection,是GNU项目中的开源编译器集合,支持C、C++等多种语言。作为C语言程序员的重要工具,GCC具备跨平台性、高度可配置性及丰富的优化选项等特点。通过简单示例,如编译“Hello, GCC!”程序 (`gcc -o hello hello.c`),展示了GCC的基础用法及不同优化级别(`-O0`, `-O1`, `-O3`)对性能的影响。GCC还支持生成调试信息(`-g`),便于使用GDB等工具进行调试。尽管有如Microsoft Visual C++、Clang等竞品,GCC仍因其灵活性和强大的功能被广泛采用。
122 1
|
3月前
|
编译器 C语言 计算机视觉
C语言实现的图像处理程序
C语言实现的图像处理程序
144 0
|
6月前
|
存储 C语言
简单c语言程序举例
简单c语言程序举例
76 1
|
1月前
|
存储 文件存储 C语言
深入C语言:文件操作实现局外影响程序
深入C语言:文件操作实现局外影响程序
|
2月前
|
存储 编译器 程序员
C语言程序的基本结构
C语言程序的基本结构包括:1)预处理指令,如 `#include` 和 `#define`;2)主函数 `main()`,程序从这里开始执行;3)函数声明与定义,执行特定任务的代码块;4)变量声明与初始化,用于存储数据;5)语句和表达式,构成程序基本执行单位;6)注释,解释代码功能。示例代码展示了这些组成部分的应用。
93 10
|
3月前
|
自然语言处理 编译器 C语言
C语言程序的编译
C语言程序的编译
64 2
|
4月前
|
前端开发 C语言 C++
C语言03----第一个程序HelloWorld(vs版)
C语言03----第一个程序HelloWorld(vs版)
|
5月前
|
C语言 图形学 C++