c的链接详解
多目标文件的链接
- #include <stdio.h>
- #define STACKSIZE 1000
- typedef struct stack {
- int data[STACKSIZE];
- int top;
- } stack;
- stack s;
- int count = 0;
- void pushStack(int d)
- {
- s.data[s.top ++] = d;
- count ++;
- }
- int popStack()
- {
- return s.data[-- s.top];
- }
- int isEmpty()
- {
- return s.top == 0;
- }
- #include <stdio.h>
- int a, b;
- int main()
- {
- a = b = 1;
- pushStack(a);
- pushStack(b);
- pushStack(a);
- while (! isEmpty()) {
- printf("%d\n", popStack());
- }
- return 0;
- }
编译方式:
定义和声明
static和extern修饰函数
- int pushStack(int);
- int popStack(void);
- int isEmpty(void);
编译器往往不知道去哪里找函数定义,像上面的例子,我让编译器编译main.c,而这几个函数定义却在stack.c里,编译器无法知道,因此可以用extern声明。修改link.c如下:
- #include <stdio.h>
- int a, b;
- extern void pushStack(int d);
- extern int popStack(void);
- extern int isEmpty(void);
- int main()
- {
- a = b = 1;
- pushStack(a);
- pushStack(b);
- pushStack(a);
- while (! isEmpty()) {
- printf("%d\n", popStack());
- }
- return 0;
- }
这样编译器就不会报警了。这里extern关键字表示这个标识符具有External Linkage.pushStack这个标识符具有External Linkage指的是:如果link.c和stack.c链接在一起,如果pushStack在link.c和stack.c中都声明(在stack.c中的声明同时也是定义),那么这些声明指的是同一个函数,链接后是同一个GLOBAL符号,代表同一个地址。函数声明中的extern可以省略不写,不屑extern的函数声明也表示这个函数具有External Linkage。
- /* foo.c */
- static void foo(void) {}
- /*main.c*/
- void foo(void);
- int main(void) { foo(); return 0;}
编译链接在一起会出错,原因是:
static和extern修饰变量
- #include <stdio.h>
- int a, b;
- extern void pushStack(int d);
- extern int popStack(void);
- extern int isEmpty(void);
- extern int count;
- int main()
- {
- a = b = 1;
- pushStack(a);
- pushStack(b);
- pushStack(a);
- printf("%d\n", count);
- while (! isEmpty()) {
- printf("%d\n", popStack());
- }
- return 0;
- }
变量count具有external linkage,它的存储空间是在stack.c中分配的,所以link.c中的变量声明extern int count;不是变量定义,因为它不分配存储空间。
区别
头文件
- #ifndef STACK_H
- #define STACK_H
- #define STACKSIZE 1000
- typedef struct stack {
- int data[STACKSIZE];
- int top;
- } stack;
- extern void pushStack(int d);
- extern int popStack(void);
- extern int isEmpty(void);
- #endif
这样,在link.c里就只需要包含这个头文件就可以了,而不需要写三个函数声明了:
- #include <stdio.h>
- #include "stack.h"
- int a, b;
- extern int count;
- int main()
- {
- a = b = 1;
- pushStack(a);
- pushStack(b);
- pushStack(a);
- printf("%d\n", count);
- while (! isEmpty()) {
- printf("%d\n", popStack());
- }
- return 0;
- }
为什么#include <stdio.h>用角括号,而#include "stack.h"用引号?原因:
- 对于用角括号包含的头文件,gcc首先查找-I选项指定的目录,然后查找系统的头文件目录(通常是/usr/include)
- 对于用“”包含的头文件,gcc首先查找包含头文件的.c文件所在的目录,然后查找-I选项指定的目录,然后查找系统的头文件目录
- 使预处理的速度变慢了,要处理很多本来不需要处理的头文件
- 如果a.h包含了b.h,然后b.h又包含了a.h的情况,预处理就陷入死循环了
- 头文件按有些代码不允许重复出现
c的链接详解的更多相关文章
- Linux 链接详解----静态链接实例分析
由Linux链接详解(1)中我们简单的分析了静态库的引用解析和重定位的内容, 下面我们结合实例来看一下静态链接重定位过程. /* * a.c */ ; void add(int c); int mai ...
- Linux链接命令及软链接、硬链接详解
命令ln详解 命令ln,所在路径为: 可以看到,它的路径为:/usr/bin/ln,因此,它的执行权限是所有用户 命令的基本功能是创建链接文件(硬链接),例如:ln /etc/issue /tmp 选 ...
- mysql数据库表间内外链接详解
1. 内连接(自然连接) 2. 外连接 (1)左外连接 (左边的表不加限制)(2)右外连接(右边的表不加限制)(3)全外连接(左右两表都不加限制) 3. 自连接(同一张表内的连接) SQL的标准语法: ...
- Linux 链接详解----动态链接库
静态库的缺点: 库函数被包含在每一个运行的进程中,会造成主存的浪费. 目标文件的size过大 每次更新一个模块都需要重新编译,更新困难,使用不方便. 动态库: 是一个目标文件,包含代码和数据,它可以在 ...
- Linux 链接详解(2)
可执行文件加载执行过程: 上一节我们说到ELF文件格式,静态库的符号解析和重定位的内容.这一节我们来分析一下可执行文件. 由上一节我们知道可执行文件也是ELF文件,当程序被加载器加载到内存时是按照EL ...
- Linux 链接详解(1)
可执行文件的生成过程: hello.c ----预处理---> hello.i ----编译----> hello.s -----汇编-----> hello.o -----链接- ...
- linux 软/硬链接详解
SYNOPSIS ln [OPTION]... [-T] TARGET LINK_NAME (1st form) ln [OPTION]... TARGET (2nd form) ln [OPTION ...
- Linux 软硬链接详解
软链接 软链接: 类似于windows的快捷方式,—>文本文件,但是包含了真实文件的地址 源文件删除,则软连接也删除 软链接可以放在任何文 ...
- linux ln链接详解
1.序 Linux具有为一个文件起多个名字的功能,称为链接.被链接的文件可以存放在相同的目录下,但是必须有不同的文件名,而不用在硬盘上为同样的数据重复备份.另外,被链接的文件也可以有相同的文件名,但是 ...
随机推荐
- WINDOWS 的 MKLINK : 硬链接,符号链接 : 文件符号链接, 目录符号链接 : 目录联接
玩转WIN7的MKLINK 引言: 换了新电脑,终于再次使用上啦WIN7 ,经过一个周每天重装N次系统,... ... ... ... 在xp系统下,junction命令要用微软开发的小程序 junc ...
- Overview of MySQL Programs
http://blog.163.com/digoal@126/blog/static/16387704020110198756512/
- 快速安装自己的Sublime系列
GitHub:http://liu12fei08fei.github.io/html/2sublime.html 安装插件管理(Package Control): Sublime Text 支持大量插 ...
- 26复杂类型比较,使用Compare .NET objects组件
关于比较对象,在"06判等对象是否相等"中大致可以总结为: 关于比较方法: ● 实例方法Equals(object obj)既可以比较值类型,也可以比较引用类型 ● 静态方法E ...
- 关于deselectRowAtIndexPath
有没有遇到过,导航+UITableView,在push,back回来之后,当前cell仍然是选中的状态.当然,解决办法简单,添加一句[tableView deselectRowAtIndexPath: ...
- tomcat 的缓存机制
事出做项目时一个jsp页面修改后一直没有读出来,后来仔细研究了下tomcat才发现 当请求jsp页面时,Tomcat会分派给JspServlet来处理,在jspServlet的方法 service() ...
- 单点登录 之 OAuth
OAuth2.0是什么 OAuth2.0是什么——豆瓣和QQ的故事 OAuth简单说就是一种授权的协议,只要授权方和被授权方遵守这个协议去写代码提供服务,那双方就是实现了OAuth模式. 举个例子,你 ...
- 让子弹飞Demo版
让子弹飞是我非常喜欢的一款游戏.今天的目标就是利用cocos2dx 3.0 和box2d 打造一款这样的类型游戏的Demo版.本来cocos2dx 3.0 已经封装了physicals模块,可是我在使 ...
- AIX加入�能够telnet远程连接账号方法
AIX 中加入�账号能够使用命令mkuser 和 SMIT 两种方式,这里介绍SMIT方式 1.使用root 账号登录AIX 2.输入 smitty user 3.选择Add a User 4.输入& ...
- [Android UI] ActionBar 自定义属性
actionbar 默认放在顶部, 如果在application或者activity中加入 android:uiOptions="splitActionBarWhenNarrow" ...