你的位置:首页 > 操作系统

[操作系统]linux下c程序的链接、装载和库


  读完《程序员的自我修养--链接、装载和库》相关章节,想来总结一下,若有错误,请指正,多谢。

1. 什么叫目标文件?

    你的工程里有很多xxx.c这样的源文件,这些文件是文本文件,只有人能够认识(当然编译器认识),但是,cpu可不认识。问题就是,真正执行指令的是cpu。

    让编译器翻译一下(这里面有很多过程,这不是这篇文章的重点),一般来说,一个xxx.c文件就能翻译成一个xxx.o,这就是目标文件了。

    一个源文件就对应一个目标文件,这个目标文件就存储了有关这个源文件的所有信息了,包括在这个源文件里函数的定义,全局变量的定义,等等。

    但是,这样就可以毫无忧虑地执行这个目标文件了么?   不可以。

    一, 你这个目标文件可能没有main函数;

    二, 你这个目标文件里,可能用到了其他函数,而这些函数的定义是在其他目标文件里的。比如说,main.c 用到了 one.c 里的 void function(); 你去执行main.c 生成的main.o,肯定不行啊,因为cpu都找不到function在哪,从而function里存储的指令,当然也没法执行;

    总之,你要运行的那个文件,里面必须得存有一切函数和变量的相关信息才可以。很显然,目标文件不具有这个特性。因为,目标文件只存储了自己的信息,并不知道其他目标文件的信息。

2. 目标文件的拼接-->可执行文件

    好的,你有一个main.c 和 一个 one.c, 并且成功的生成了两个目标文件,各自存储了自身的信息,它们就是 main.o 和 one.o。

    不巧的是,main.c 里用到了 one.c 里的 void function(); 函数。这个时候,main.o 苦于找不到这个函数在哪而不得执行。而 one.o 静静的等在那,等待一个过程。

    这个过程就是链接。 

    ld 是一个指令,linux 下,可以让目标文件链接起来,拼成一个真正能用的可执行文件。

    例如这样:

    ld main.o one.o -o go

    其中 -o 后面是随意指定的,这就是可执行文件的名称。好了,这个 go 就是最终的可执行文件。你可以去执行它了。

    go 是由两个目标文件拼起来的,它当然知道所有的信息,包括 具体的 function 的指令。于是,它就可以被执行。

    现在,到了这里,我们似乎忘了另一种重要的文件,头文件。

3. 头文件是个啥?

    好吧,问题能提升你看这篇文章的乐趣。那就思考一个问题:main.c 能成功编译成 main.o么?

    刚才的过程似乎太顺利,main.c 刷一下就成了 main.o, 而问题是,你在 main.c 里使用了一个它不认得的函数 void function(); 这个竟然能编译过,顺利生成 main.o?

    你可以试试,用这样的命令:

    gcc -c main.c -o main.o

    -c 选项就是说,我要生成目标文件,而不是默认的可执行文件。你一定会得到一个【编译】错误,这个错误会告诉你,function 这个函数我不认识,败!

    【编译】错误,在源头上先防止你造出一个完全不能用的程序。

    这个时候,怎么办,main.c 确实不认得 function 函数,你总不能把 one.c 里的函数复制粘贴到 main.c 里吧(当然这是可以的,不过,low爆了)。

    那么需求如下:

    一, 不拷贝过来整个函数;

    二, 让 main.c 顺利生成 main.o。

    问题的核心就是,让 main.c 认识 function 是个啥(是函数还是变量?如果是函数,这个函数的参数有哪些?返回什么类型的值?)。

    容易,你在 main.c 源文件里加一句 

    extern void function(); // 这个函数的返回类型是 void, 并且没有参数。

    这样一来,main.c 本身就认识了 function, 注意,只是认识,但是并不知道它具体实现,也不知道这个函数在哪里。实际上,也不需要知道这么多。因为,我这一步只是生成目标文件而已。剩下的交给链接那一步。

    结论,生成目标文件,必须得让源文件认识每一个符号(变量和函数)。

    假如 one.c 是你的同事编写的,你应该让他同时编写一个头文件。省的你还要在你的 main.c 里 一行行地加上 

    extern void function1();

    extern int function2(char a);

    ...

    ...

    这种东西。

    你的同事会给你一个头文件 one.h , 这个头文件里实际上就是以上extern的内容。你只需要在 main.c 里这样干:

    #include "one.h"

    就行了,这一句就是把 one.h 整个拷贝到 main.c 里去。

4. printf 用起来挺爽的。

    printf 用起来挺爽的。

    你只用写上

    #include <stdio.h>

    让你的 main.c 认识这个函数就能用了。

    不过,问题是,你并没有链接 printf 所在的目标文件啊!

    思考,思考,再思考!

    好吧,这不是个问题。

    实际就是,gcc 默认帮你链接了。千万不要认为,不用链接就可以!!!!

    你可以这么认为:只要是系统提供的东西,你都不用手动链接,你关心好自己的东西就行了。

 




深圳去韩国旅游报价办理韩国旅游签证跟团韩国旅游需要多少钱几月份去韩国旅游最好什么时候去韩国旅游最便宜深圳野生动物园亲水乐园什么时候开放?深圳西丽野生动物园亲水乐园怎么样? 2015深圳野生动物园五一开放项目有哪些?深圳野生动物园新闻? 2015深圳野生动物园五一活动?五一去深圳海洋天地有什么好玩的? 深圳世界之窗啤酒节是什么时候?世界之窗啤酒节攻略? 从香港过关要注意些什么? 香港油麻地有什么好吃的? 从香港到澳门坐船的票价多少?往返时间? 香港青马大桥怎么去?有哪些好玩的景点? 东南亚有什么好玩地方? 马尔代夫满月岛、天堂岛、双鱼岛哪个好? 泰国有几个飞机场?有多少个飞机场? 泰国有哪些特产?泰国有什么特产? 盘点宁德、三明、南平、莆田、龙岩桃花观赏地 2015广州长隆野生动物园奇妙的朋友拍摄地?奇妙的朋友在长隆哪里拍的? 盘点泉州、漳州桃花观赏地 2015世界之窗元宵节晚上有烟火晚会吗?深圳世界之窗元宵节烟火晚会几点? 0603YC104KAZ2A Datasheet 0603YC104KAZ2A Datasheet TAJA155K035RNJ Datasheet TAJA155K035RNJ Datasheet TAJA156K010RNJ Datasheet TAJA156K010RNJ Datasheet 加拿大签证办理流程 加拿大签证办理流程 加拿大签证办理流程 岘港天气 岘港天气 岘港天气 香港南丫岛旅游攻略 香港南丫岛旅游攻略 香港南丫岛旅游攻略