c语言入门-程序运行的过程

2023-10-30

目录

程序运行的过程

 1.编译

预编译

编译:

汇编

2.链接

1.段表的合并

2.符号表的合并和重定位

3.运行

预处理

#define

 宏实现计算

 #define和typedef

 #define的替换规则

#和##---将参数插入代码中

带有副作用的宏

 宏和函数比较

#undef---移除被定义的宏

#if---条件编译

 #if defined---判断是否被定义


程序运行的过程

编译可以分为三个部分:预编译,编译, 汇编。

 我们写的代码是文本文件(.c文件),.c文件通过编译转换为.obj文件,.obj文件通过链接转换为.exe文件(可执行文件)。可执行文件在运行环境中运行。

.obj文件---二进制目标文件   .exe---二进制可执行文件

 1.编译

由于vs是集成开发环境,所以使用linux来观察过程。

编译可以分为三个部分:预编译,编译, 汇编。

预编译

执行操作:

处理预处理指令(#include,#if……)

去掉注释

#define---宏展开

宏展开: MAX改成了100

编译:

将文本文件转化为汇编代码

词法分析

语法分析

语义分析

符号汇总

词法分析:

编译器将代码的字符序列自动转化为一系列的记号。

例如:array=(i+2)*j;

经过词法分析,得到以下这几个记号:

array ---标识符              = ---赋值

(---左圆括号                i---标识符

+---加号                    2---数字

*---乘号                     j---标识符

除了识别记号的同时,扫描器也完成了其他工作,例如,将标识符存放到符号表中,将数字,字符串常量放到文字表中。

语法分析:

语法分析器对词法分析得到的记号进行语法分析,将其化为各种表达式、或者语句等。同时进行判断,如果出现结构错误(例如:括号不匹配,逗号中英文格式……),编译器就会报告语句分析阶段错误。

语义分析:

编译器进行语义分析的是静态语义(编译期间确定),静态语义通常包括声明和类型的匹配,类型的转化。

例如:浮点型数据传给整形,发生隐式类型转化,而浮点型数据给指针,报错。

符号汇总

汇总全局符号

汇编

形成符号表。在符号表中,程序中的每个标识符都和它的声明或使用信息绑定在一起,比如其数据类型、作用范围以及内存地址。

将汇编代码转为二进制文件目标文件(.obj)

2.链接

.obj文件转化为.exe文件

1.段表的合并

一个二进制文件按照段表来存储各种信息,例如: 

 这样的每一个段表对应每一个.o文件(linux下的可执行文件)

段表合并:例如text.o和add.o文件,将两者的段表按照某种规则可以合并到一起,完成代码实现。

2.符号表的合并和重定位

段表合并,其内的符号表也会合并。合并过程中,无效的符号表信息会被有效信息代替,这就是重定位。

3.运行

1.程序载入内存,有操作系统的情况下,由操作系统进行代码运行。没有时,程序根据别的方式进入内存。

2.代码从main函数开始运行

3.调用别的函数,开辟函数栈帧。

4.代码从main函数正常结束或者异常结束。

预处理

#include<stdio.h>
int main()
{
	printf("%s\n ", __FILE__);//代码文件名
	printf("%d\n ", __LINE__);//行号
	printf("%s \n", __TIME__);//代码运行时间
		return 0;
}

#define

定义宏  定义符号

#include<stdio.h>
#define MAX 100
int main()
{
	int m = MAX;
	return 0;
}

预处理阶段---处理预处理指令---展开#include<stdio.h>的内容至800多行

预处理阶段---#define直接替换---代码里的MAX都被替换为100,MAX替换后消失

 宏实现计算

#include<stdio.h>
#define ADD(x,y) ((x)+(y))
int main()
{
	printf("%d ", ADD(3, 4));
   //x被替换为(3),y被替换为(4)
	return 0;
}

 括号的重要性---运算符的优先顺序,可能会影响值的结果

#include<stdio.h>
#define MUL(x,y) x*y
#define FUN(x,y)((x)*(y))
int main()
{
	printf("%d ", MUL(3+4, 4));
	//结果19 x替换为3+4,y替换为4 计算式:3+4*4=19
	printf("%d ", FUN(3 + 4, 4));
	//结果28 x替换为(3+4),y替换为(4) 计算式:(3+4)*4=28
	return 0;
}

 #define和typedef

#include<stdio.h>
#define  INT1 int //INT1定义为int,INT1是标识符,预编译被替换为int
typedef int INT2;//int被重命名为INT2,INT2是类型
int main()
{
	int m = 10;
	printf("%d ", m);
	INT1 a = 20;
	printf("%d ", a);
	INT2 b = 30;
	printf("%d ", b);
	return 0;
}
#include<stdio.h>
typedef int* type1;//int*被重命名为type1,type1是类型
#define type2 int*//type2是标识符,内容是int*,预编译产生替换
int main()
{
	type2 a, b;
	//type2被替换为int*,int*a,b ---a是int类型的指针,b是int类型的变量
	type1 c, d;
	//type1是一种类型---c,d都是int类型的指针
	return 0;
}

 #define的替换规则

#define在预编译期间替换

宏不可以实现递归,但是可以嵌套使用,例如:ADD(ADD(3,4),5)

#和##---将参数插入代码中

在C语言中宏定义中,#的功能是将其后面的宏参数进行字符串化操作。

#include<stdio.h>
#define print( ch)	printf(""#ch"的值%d\n", ch)
#define fun(ch) printf(""#ch"")
int main()
{
	int a = 10;
	printf("%c的值%d\n", 'a', 10);
	int b = 20;
	printf("%c的值%d\n",'b',b);
	print(a);
	//相当于printf("%c的值%d\n", 'b', b);
	print(b);
	fun(ch);//打印ch
	//相当于 printf("%s",ch)
	return 0;
}

##是连接符,前加##或后加##,将标记作为一个合法的标识符的一部分,不是字符串.多用于多行的宏定义中。

#include<stdio.h>
#define fun(x,y) x##y
int main()
{
	int arr = 10;
	printf("%d ", fun(ar, r));//ar r在fun里面连接成为arr
	return 0;
}

带有副作用的宏

替换过程中,例如下列代码的自增操作,使变量的值方式改变

#include<stdio.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
	printf("%d ", MAX(3 + 2, 1));
	int a = 2;
	int b = 3;
	printf("%d ", MAX(a++, b++));
	//((a++) > (b++) ? (x) : (y));
	//  2>3判断,a变为3,b变为4
	return 0;
}
#include<stdio.h>
int MAX(x, y)
{
	int m = x > y ? x : y;
	return m;
}
int main()
{
	printf("%d ", MAX(3 + 2, 1));
	int a = 2;
	int b = 3;
	printf("%d ", MAX(a++, b++));
	// 函数传入2,3 打印结束之后a为3,b为4
	printf("%d ", a);
	printf("%d ", b);
	return 0;
}

 宏和函数比较

宏优点:

  • 函数调用,每一次都要开辟函数栈帧,时间占用多,宏在预编译时直接替换,时间性能上更好,运算速度快。
  • 函数有参数的类型要求,宏没有类型要求

宏缺点:

  • 不进行类型检查,容易出错
  • 宏代码在每一次调用,都要插入调用函数中,如果宏内容十分长,空间占用多。而函数调用的代码就那一个,不会插入进调用函数。
  • 宏不能调试,函数可以调试
  • 宏在计算上有可能产生错误(运算符优先级,副作用的参数……)
  • 宏不能递归,函数可以递归

#undef---移除被定义的宏

#include<stdio.h>
#define ADD(x,y) ( (x)+(y))
int main()
{
	printf("%.2lf ", ADD(2.4 , 0.9));
#undef ADD//ADD被移除
	printf("%.2lf ", ADD(2.4 , 0.9));//error :无法引用的外部符号
	return 0;
}

#if---条件编译

#if开始,#endif结束

#if的条件为真,#if和#endif之间的代码参与编译,为假时,不进行编译

在预编译期间进行,#if条件满足,预编译期间让代码参入了后续编译,不满足,则后续代码不会出现#if和#endif的中间代码内容。

#include<stdio.h>
int main()
{
#if 0//为假
	printf("hi");
#endif

	printf("hello");//打印hello
return 0;
}

 多分支的条件编译

#include<stdio.h>
#define a 1
int main()
{
	//int a = 1;
//#if 在预编译期间运行,int a=1在编译进行,预编译时期没有a
	//可以使用宏定义
#if a<1
	printf("hi");
#elif a==1
	printf("hello");
#else 
	printf("he");
#endif
}

 #if defined---判断是否被定义

#include<stdio.h>
#define MAX 2
int main()
{
#if defined MAX
	printf("yes");
#else
	printf("no");

#endif

	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言入门-程序运行的过程 的相关文章

  • 生信必会格式:Fasta & Fastq 简介及转换

    文章目录 前言 FASTA 例子 血红蛋白 的核酸和蛋白质序列 FASTQ FASTA FASTQ 对比 FASTQ 转为 FASTA 使用基本的命令 sed paste awk 使用现有工具 Bioawk Seqtk FASTA 到 FA
  • sql注入详细解释

    sql注入以及应对措施 sql注入是什么 sql注入的危害 sql注入的几种方式 数字型注入 字符串注入 关于mybatis中传递变量用 的原因 sql注入是什么 sql是我们操作数据库与其交互的语言 而sql注入是用户将Web页面的原UR
  • waymo数据集下载

    下载waymo数据集下载报错 gsutil不能使用怎么办 安装谷歌云 gcloud init gcloud auth login gcloud auth application default login gsutil config 然后就

随机推荐

  • Linux内核调度框架和CFS调度算法

    进程调度 暂时以2 6 24内核版本讲解 该版本是CFS调度器注入Linux内核之后的第二个版本 在框架和数据结构上与4 x之后没有本质上的区别 但是由于4 x对CFS调度做了很大的优化 代码量暴增10倍之多 故不容易把握算法与框架的本质
  • 【两阶段鲁棒优化问题】用列和约束生成方法求解两阶段鲁棒优化问题(Matlab代码实现)

    个人主页 研学社的博客 欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 文献来源 4 Matlab代码及文章 1 概述 文献来源 鲁棒优
  • vue后台水印实现

  • RGB与YCbCr

    1 RGB RGB色彩模式是工业界的一种颜色标准 是通过对红 R 绿 G 蓝 B 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的 RGB即是代表红 绿 蓝三个通道的颜色 这个标准几乎包括了人类视力所能感知的所有颜色 是目前运
  • 成功解决Array Index Out Of Bounds Exception问题

    成功解决Array Index Out Of Bounds Exception问题 目录 解决问题 解决方法 解决问题 Array Index Out Of Bounds Exception 解决方法 数组索引越界异常 即数组下标号超出数组
  • Spring Cache --- @Cacheable/@CachePut/@CacheEvict注解的原理深度剖析和使用

    这里只是部分 需要深入了解可以看原著 原文链接 https blog csdn net f641385712 article details 94570960 关于Spring的缓存注解 一共有如下5个 1 Cacheable 缓存 sin
  • 实战:10 种实现延迟任务的方法,附代码!

    捡田螺的小男孩 2022 08 04 07 45 发表于广东 以下文章来源于Java中文社群 作者磊哥 Java中文社群 Java实用文章聚集地 程序员田螺 专注分享后端面试题 包括计算机网络 MySql数据库 Redis缓存 操作系统 J
  • 新Kubeflow,新征程 (一):简化部署体验

    综述 2017年底 奥斯汀的Kubecon上 Google项目的产品经理 David Aronchick 和首席工程师 Jeremy Lewi将Kubeflow这个项目带到了大家的视野里 经过一年的发展 在2018年的西雅图的Kubecon
  • Python中selenium实现文件上传所有方法整理总结

    pyAutoGUI官方文档 https pyautogui readthedocs io en latest 文件上传是所有UI自动化测试都要面对的一个头疼问题 今天博主在这里给大家分享下自己处理文件上传的经验 希望能够帮助到广大被文件上传
  • ​stp文件转ply

    什么是一 stp 文件 STP 文件是用于在 CAD 和 CAM 应用程序之间交换产品数据的 3D CAD 文件 它包含有关 3D 对象的信息 并以类似于STEP文件格式的方式保存 STP 文件根据STEP应用程序协议 ISO 10303
  • Qt设置label的文字自动换行、高度随内容调整、上下可滚动

    Qt初学者 想要用label控件实现一个用于显示文字信息的文本框 要求文字自动换行 label高度随内容调整 上下可滚动 为了实现滚动 使用ScrollArea控件 将要显示文字的label放到这个ScrollArea里 然后设置Scrol
  • 控制台报错:failed to load resource: net:err_cert_date_invalid的解决办法

    原因 浏览器端屏蔽了不安全的连接 解决办法 1 打开检查页面里 Network 网络 2 双击name 名称 下红色报错的地方 会出现以下界面 3 点击高级 下面会出现提示 点击继续前往 不安全 4 回到之前的页面刷新 问题就解决了
  • Exception of type 'System.OutOfMemoryException' was thrown.

    OutOfMemoryException Exception of type System OutOfMemoryException was thrown 在装有4G物理内存的32位OS机器上内存不足 原因是 The common lang
  • array type has an incomplete element type

    一 错误详情 array type has an incomplete element type 二 错误分析 1 错误代码 int readInfo int B int n int findMax int B int n int m 2
  • 英伟达Tesla T4 显卡编解码能力测试

    显卡基本参数 Timestamp Fri Aug 27 10 04 12 2021 Driver Version 460 32 03 CUDA Version 11 2 Attached GPUs 8 FB Memory Total 151
  • 计算机网络【IP数据包首部的各个字段详解】

    文章目录 一 网络层简述 二 网络层首部 版本 首部长度 区分服务 总长度 三 网络层首部 标识 标志 片偏移 四 网络层首部 生存时间 协议 首部检验和 五 可选字段 填充字段 源IP 目标IP 六 总结 一 网络层简述 一个IP数据包的
  • Windows计划任务(手动执行脚本正常,定时执行不生效)

    ps 本公司是一家游戏公司 目前有一台win服务器上面搭建MySQL数据库 现在需要做MySQL数据库的备份然后上传到Linux服务器上 bat 脚本写好以后手动双击测试多遍正常上传备份文件 可每当计划任务去执行的时候往往出错 不执行上传L
  • 系统开发设计基础(二)

    删除
  • 信号的傅里叶分析之傅里叶级数

    1 为什么要进行傅里叶分析 信号分析方法主流方法有 1 时域分析 以冲激信号为基本信号 任意输入信号可分解为一系列冲激信号 2 频域分析 以正弦信号和虚指数信号为基本信号 将任意输入信号分解为一系列不同频率的正弦信号或者虚指数信号之和 独立
  • c语言入门-程序运行的过程

    目录 程序运行的过程 1 编译 预编译 编译 汇编 2 链接 1 段表的合并 2 符号表的合并和重定位 3 运行 预处理 define 宏实现计算 define和typedef define的替换规则 和 将参数插入代码中 带有副作用的宏