linux下c程序的链接、装载和库(1)
读完《程序员的自我修养--链接、装载和库》相关章节,想来总结一下,若有错误,请指正,多谢。
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 默认帮你链接了。千万不要认为,不用链接就可以!!!!
你可以这么认为:只要是系统提供的东西,你都不用手动链接,你关心好自己的东西就行了。
linux下c程序的链接、装载和库(1)的更多相关文章
- Linux下进行程序设计时,关于库的使用:
一.gcc/g++命令中关于库的参数: -shared: 该选项指定生成动态连接库: -fPIC:表示编译为位置独立(地址无关)的代码,不用此选项的话,编译后的代码是位置相关的,所以动态载入时,是通过 ...
- linux下c程序的链接、装载和库(2)
5. 重定义错误. 一个最终的可执行文件里,绝对不允许出现两个同名的全局变量,也不允许出现同名的全局函数. 全局函数:只要不用 static 修饰符修饰的函数,全部都是全局的. 全局变量:函数外声明定 ...
- linux下c程序的链接、装载和库(3)
9. 目标文件放在一起-->静态库. 你的同事给出的目标文件太多了,从 one.o two.o …… …… 一直到 xxx.o. 好的,你如果真正想用,你的同事提供的这些现有的目标文件,你得做三 ...
- Linux下C程序的编辑,编译和运行以及调试
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- linux下软、硬链接的创建和删除
linux下软.硬链接的创建和删除 在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复 ...
- Linux下显示运行时链接(运行时加载)
目录 介绍 如何加载动态库 dlopen() 第一个参数: 被加载动态库的路径 第二个参数: flag表示函数符号的解析方式 dlopen 返回值 dlsym() 参数: 返回值 符号优先级 dler ...
- linux下c程序调用reboot函数实现直接重启【转】
转自:http://www.blog.chinaunix.net/uid-20564848-id-73878.html linux下c程序调用reboot函数实现直接重启 当然你也可以直接调用syst ...
- 位图文件(BMP)格式以及Linux下C程序实现(转)
源:位图文件(BMP)格式以及Linux下C程序实现 说到图片,位图(Bitmap)当然是最简单的,它是Windows显示图片的基本格式,其文件扩展名为*.BMP.由于没有经过任何的压缩,故BMP图 ...
- Linux下C程序内存泄露检测
在linux下些C语言程序,最大的问题就是没有一个好的编程IDE,当然想kdevelop等工具都相当的强大,但我还是习惯使用kdevelop工具,由于没有一个习惯的编程IDE,内存检测也就成了在lin ...
随机推荐
- C#并行编程-并发集合
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
- iOS-观察者模式
cocoa框架中很多地方都使用了观察者模式 一.KVO Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.每次指定的被观察的对象的属性被修改后, ...
- 【WP开发】实现“摇一摇”功能
尽管我的微信是每八个月登录一次,但我相信各位玩得比我多.微信有一个“摇一摇”功能,这个功能其实是利用了加速度传感器来实现的,这个传感器,我估计再低端的手机都会有的,这是严重基本的传感器. 重力加速度既 ...
- 做网站用UTF-8编码还是GB2312编码?
经常我们打开外国网站的时候出现乱码,又或者打开很多非英语的外国网站的时候,显示的都是口口口口口的字符, WordPress程序是用的UTF-8,很多cms用的是GB2312. 经常我们打开外国网站的时 ...
- 自动生成Mapper和Entity工具MybatisGenerator的使用
新建一个XML文件crmGeneratorConfig.xml,文件具体内容如下.把MybatisGenerator.zip解压出来,把MybatisGenerator文件夹复制到Eclipse安装目 ...
- java中paint方法和paintComponent方法的不同
/* 1.由Component.java源代码中可以看见其中的paint()方法体是空的,在Container中重写了该方法,其子类Window等也重写了该方法 2.由JComponent.java源 ...
- Docker 有什么优势?
1.什么是容器? 依托与linux 内核功能的虚拟化技术 2. docker 是什么? 能够把应用程序自动部署到容器的开源引擎 3. docker 跟原有的工具有何区别? 传统的部署模式是:安装(包管 ...
- android用讯飞实现TTS语音合成 实现中文版
Android系统从1.6版本开始就支持TTS(Text-To-Speech),即语音合成.但是android系统默认的TTS引擎:Pic TTS不支持中文.所以我们得安装自己的TTS引擎和语音包. ...
- 十款让 Web 前端开发人员更轻松的实用工具
这篇文章介绍十款让 Web 前端开发人员生活更轻松的实用工具.每个 Web 开发人员都有自己的工具箱,这样工作中碰到的每个问题都有一个好的解决方案供选择. 对于每一项工作,开发人员需要特定的辅助工具, ...
- 关注经典:CSS Awards 获奖网站作品赏析《第一季》
每天都有很多新的网站推出,其中不乏一些设计极其优秀的作品.这个系列的文章,我为大家挑选了2012年赢得 CSS Awards 大奖的50个最佳网站.这些鼓舞人心的网站作品代表了网页设计的最高水平,相信 ...