现在的位置: 首页 > 综合 > 正文

从helloworld.c到a.out(1)概述

2016年08月25日 ⁄ 综合 ⁄ 共 1217字 ⁄ 字号 评论关闭

不管你是否写过,你一定看过或者听说过下面这段程序

#include <stdio.h>

int main(int argc, char* argv[]){
    printf("hello, hell world \n");
    return 0;
}

你写完这个,然后习惯性的gcc helloworld.c,然后./a.out,然后终端打出 hello, hell world

所有人都知道,写完C/C++程序之后要编译,要生成可执行文件,可是不是所有人都知道为什么要编译,为什么要生成可执行文件,为什么编译会报错,这些错误是怎么被查出来的,可执行文件为什么可执行。

的确,计算机科学发展到现在,层次概念非常分明,写一个应用程序,不用像二三十年以前还要跟硬件打交道,所以在不了解很多如以上问题的答案的情况下,也能写出来可以运行的程序。

好,现在问题来了,谭爷爷的绿皮书上讲解指针的章节有一个类似下面的例子:

void swap(int* a, int* b){//大概是这样吧,记不太清楚了

if(!a || !b)

return;

int tmp = *a;

*a = *b;

*b = tmp;

return;

}

有一天你在网上看见交换两个数的值还可以这么写,所以你自己也写了一个:

你用*a ^ *b = *a ^ *b = *a ^ *b;(或者*x = *x + *y;*y = *x - *y; *x = *x - *y;)取代了上面的函数中的实际交换过程,你编译然后./a.out。

如下图所示代码:


然后跑出来一个


但是跑出来的结果却是酱紫。。。

很明显这个问题的答案就隐藏在本文的标题“从helloworld.c到a.out”中,

这个答案不会在现在给出,后续讲到编译器优化的时候会详细解释。


言归正传,下面介绍下,从.c文件到终端出现输出中间到底经历了什么,这些过程就是这一系列文章的主题,

很多东西我也是一知半解,以前的知识零零散散,

希望这一系列博客写完,能像jobs先生说的那样connected all dots of my memory,

预处理->编译->连接->装载->运行

其中编译又可以细分为(词法分析->语法分析->语义制导分析->源代码优化->目标代码生成->目标代码优化)

链接是指将将各个源代码生成的目标文件按照某种规则组合在一起,形成一个库,或者与其他库组合成一个可执行文件(ELF)的过程,

这个过程比较复杂,同时,链接分为动态连接和静态链接,对应的,库文件也有动态库和静态库之别。

虽然helloworld.c只有一个源文件,但是他在连接的时候会链接上一些你看不见的文件。

假设将hellocworld.c分为两个文件,分别编译成.o,然后ld这两个object文件,链接一定不会成功。


ps:精确点来说,我们常说的编译实际上是以上的预处理,编译和链接的总称,在本文及以后的一系列文章中,我们称之为宏观意义上的编译。

       而上面实际的编译过程(词法分析->语法分析->语义制导分析->源代码优化->目标代码生成->目标代码优化),我们称之为微观意义上的编译。

抱歉!评论已关闭.