欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c语言程序的执行过程(以输出hello,world为例)

程序员文章站 2022-06-28 21:47:32
...

1.c源文件的存储

任何数据在计算机中都以二进制的样式进行存储,即0和1两种存储表示,那么c源文件中的各种字符要想存储在计算机中作为可执行的指令,那么必须得以二进制0或1的形式存储在其中,因此,需要将c源文件的需要被以某种方式“翻译”成二进制存储进计算机。

数据类型表示数字的类型如int,double 等类型在内存中是以换算的二进制存的,而字符类型等在内存中是以ASCII存的,这个通过查ASCII得到相应的二进制,然后存放于内存。
比如:32767 当作int型 为整数,利用除2取余法得到相应的二进制数存于内存(本来应该存补码,但是正数的补码和原码相同)所占的内存空间跟其对应的数据类型有关,可能还与机器有关,
而32767 当作字符  即“32767”,这时应该分解‘3’,‘2’,‘7’,‘6’,‘7’,然后查对应的ASCII码 对应的值为:0011001 00110010 00110111 00110110 00110111  所以在存放的即为该二进制的组合,且占5个字节的内存
将指定的字符“翻译”成对应二进制文件需要“统一”的“密码本”,使得在任何一台计算上c源文件都以相同的二进制形式存储。而翻译这个c源文件的“密码本”就是ASCII码。

ASCII使用8位二进制数表示256个字符,这些字符包括32个大小写字符,10个数字,以及其他的字符,例如,一个输出“hello,world”的ASCII为

#include <stdio.h>

int main(void)
{
    printf("hello,world\n");
	return 0;
}

c语言程序的执行过程(以输出hello,world为例)

即符号#的ASCII码为35,i的ASCII为105......

而ASCII中35的二进制为0010 0011,i为0110 1001......

因此c源文件在计算机中存储为0010 0011 0110 1001 ......

2.c源文件的编译

Linux系统上的编译hello.c:

c语言程序的执行过程(以输出hello,world为例)

c源文件仅仅是以二进制的形式存储在计算机中,而我们要实现的是计算机输出“hello,world”,那么需要将这些二进制文件编译成计算机可以识别的指令,“告诉”计算机我们要输出“hello world”。

构成这些计算机可以识别的二进制指令称为机器语言,因此,c语言的编译就是编译成机器语言共计算机执行。

在Linux系统中,将c源文件编译成可执行的二进制指令文件是由gcc编译器完成的,gcc是gnu组织的开发的编程语言编译器。

输出“hello,world”的hello.c的编译流程:

c语言程序的执行过程(以输出hello,world为例)

编译一个hello.c的程序总共分为四个阶段:预处理,编译,汇编和链接

预处理阶段:预处理阶段是根据程序中字符#开头的命令并执行相关操作,在holle.c中#开头的第一行为#include <stdio.h>,预处理器就读取c库中的stdio.h的内容将其插入到hello.c文本中生成一个新的文件hello.i;

编译阶段:编译器ccl将hello.i翻译汇编程序储存在文件hello.s中,其中的main作为一个函数给出了机器语言的输出指令;

	.file	"hello.c"
	.section	.rodata
.LC0:
	.string	"hello,world"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$.LC0, %edi
	movl	$0, %eax
	call	printf
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

汇编阶段:汇编器将hello.s中的汇编语言翻译成计算机可以识别的机器语言存为hello.o二进制文件;

链接阶段:在c源文件中我们引用了printf打印函数,而计算机要识别这个函数也要由二进制指令组成。而在头部文件中stdio.h作为c语言的标准库,其中已经定义了printf的接口,系统根据接口去读取已经写好的printf.o二进制指令文件,将其与hello.o文件合并为hello二进制文件,称为可执行目标文件或可执行文件。

3.hello文件的执行过程

Linux上执行hello打印输出:

c语言程序的执行过程(以输出hello,world为例)

打开shell从键盘输入./hello,shell会优先把输入的字符串当做内置命令,若不是则会将其当做可执行文件的名字处理。shell将计算机I/o接口连接的输入设备输入的字符串通过总线接口存入寄存器,再存入内存中。

从键盘中读取shell命令流程:

c语言程序的执行过程(以输出hello,world为例)

完成./hello输入后,当从键盘上输入回车后,shell得知命令输入完成,开始执行一系列指令从磁盘复制hell文件到内存中,流程如下:

c语言程序的执行过程(以输出hello,world为例)

当hello文件被复制到主存之后,处理器开始执行hello程序的main程序的指令。流程是将这些指令从主存复制到寄存器,再从寄存器复制到显示设备上,最终显示到屏幕上,流程如下图:

c语言程序的执行过程(以输出hello,world为例)



相关标签: c语言编译流程