设为首页 收藏本站
查看: 706|回复: 0

[经验分享] linux extern关键字的作用

[复制链接]

尚未签到

发表于 2016-2-24 15:26:37 | 显示全部楼层 |阅读模式
  extern 的作用是起到一个链接作用!
  
  1.简单的例子。
  
  //包含头文件是为了声明这个函数,表示这个函数已经被定义过了,已经生产过二进制代码了。

#include <stdio.h>
int main(int argc, char **argv)
{
printf("hello world!");
return 0;
}

  
  
DSC0000.jpg
  
  假设现在是一个大工程,A.c include B.h  C.h,现在又有B.c  C.c文件。编译过程如何呢?
  
  编译是单个文件进行的。这句话如何理解呢?
  
  计算机最终执行的是二进制代码,我们用的库都是二进制机器码,CPU不停地吃,来执行指令。假设我们写好了许多
  
  许多好用的函数,从文本文件(main.c)编译成了二进制机器码文件(main.so,即库文件)。现在我需要利用这些基础的
  
  函数形成重新组合调用,获得一些新的功能。比方说,我又添加了extra.c 来调用main.c中的函数。这时候就有了两种办法来生成新的二进制文件。
  
  一种就是把main.c extra.c作为一个整体的whole.c来编译,生成whole.so二进制文件。从方法学的角度讲,这是整体
  
  法。当然这是个不好的方法。聪明的办法分而治之,划分,化整体为局部。先把后来的extra.c编译好了之后,再整体化处
  
  理,这个额外的过程就是链接。因为编译好的二进制代码是没必要重新生成的,只需要新的二进制代码执行后,跳入到编译
  
  好的二进制代码那里执行就好了。
  
  又回到我们假设的工程,现在有三个文件,A.c, B.c, C.c,我们可以一个个编译成A.o, B.o, C.o,因为A调用了B,C,
  
  所以最后的连接过程是不会丢失这个调用的关系的。链接的过程就像是声明一种边界一样。我在这里声明:这个是编译好的
  
  文件,你不需要编译,你自己管你自己的就行了。最后连接器会把这个边界给缝合起来的。
  
  
  在例子中,我们看到,我们include 了<stdio.h>,这里声明了好多函数,就是告诉编译器,操作系统中这些函数都已经
  
  实现了,(至于在哪里,我们最后再谈。),所以这个printf是合法的,然后我们用gcc -c file.c ,可以发现生成了file.o。
  
  file.o 包含了printf的一个符号地址,用链接程序再替换一下,换成物理地址,gcc file.c -o file.exe,file.exe就包含
  
  真正的物理地址了,就可以去call库文件中的函数了。这样程序就会执行了。
  
  同理,我们再试试这样写:
  
  extern int printf (__const char *__restrict __format, ...);

//printf这个函数是在库文件(libc.so.6 => /lib/tls/i686/cmov/libc.so.6)
//中已经被编译成了二进制代码
int main(int argc, char **argv)
{
printf("hello world!");
return 0;
}

   我们用gcc -c file.c可以看到命令是可以成功的。这里的extern也就是相当于#include <stdio.h>一样,告诉编译器一个
  
  边界,这个,我是有二进制代码的!!(在某某二进制的库文件里面) 放过他,请继续编译。如果我们既没有头文件,也没
  
  声明这个是个"已经编译好的二进制函数“(extern 可以看成是个 ”二进制函数“,我自己发明的,不正规)。编译一下如何?
  
  结果是这个: 
  
  file.c:7: warning: incompatible implicit declaration of built-in function ‘printf’
  
  编译会给个警告,自作聪明地给你反推出一个”二进制“函数,自己假设这个函数已经有了,然后连接搜索库,结果真找了,
  
  呵呵。但是它的反推功能如何,我不知道。
  
  再假设,我们自己的函数,调用了一个sayhello(),结果sayhello()这个函数根本就没变成”二进制“函数,所以肯定会爆
  
  一个函数没有的错误。
  
  看到这里,我们已经大概明白了编译的过程。这是一个万丈高楼平地起的过程,一个个函数被”二进制“化,一个个新的再
  
  依赖这些”二进制函数“ 。库的过程就是这样,常用的所有基本功能编译好了,打成包,就成了库文件。新的开发依赖这个库
  
  ,所以我必须有这些库,而后,我自己再把自己的函数编译,打包,归档,形成了新的库,这样就形成了库的依赖关系。和
  
  java的jar包是一个道理。
  
  从这里,我们也可以得出一个结论:头文件是开发的非必要条件。因为可以不include,直接手工声明,也是可以编译,
  
  链接成功了。(头文件只是起到了一个方便的作用)。
  
  如果你要用C++开发mysql, 如果有合适的库文件,不需要它的头文件,也是可以开发的呦,不过我没试,
  
  所以不知道能不能成功,呵呵。注:(完整版的mysql,都是由开发包的,头文件,库文件一应俱全)。
  
  最用我们用ldd明来看看都依赖了哪些库?
  
  
  bard@bard-desktop:~/sharing$ ldd file.exe

linux-gate.so.1 =>  (0x002fe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00a5d000)
/lib/ld-linux.so.2 (0x00c56000)
bard@bard-desktop:~/sharing$
   最后,我们做一下拓展训练:
  
  首先只有一个文件:
  
  


int main(int argc, char **argv)
{
sayHello();
return 0;
}
   
  gcc -c file.c ,我们看到是不成功的。
  
  
  第二个文件
  #include <stdio.h>


int one=1;
int two=2;
void sayHello()
{
printf("love you");
}
   
  gcc -c constant.c  是可以成功的,生成了constant.o(似乎sayHello函数已经二进制化了)
  
  
  但是这时gcc file.c -o file.exe,还是不成功,为什么呢?
  
  
  看来这个constant.o 和libc.so库文件是有区别的啊,如果我们把这个constant.o打包到libc.so中就可以了。呵呵
  
  正确做法是
  
  gcc constant.o file.c -o file.exe
  
  看来这个命令的含义是:  编译file.c 并和constant.o中的”二进制“函数sayHello进行链接。
  
  不知道,各位兄弟姐妹们是如何理解编译过程的,如果您有好的想法,请给我留言。
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-182326-1-1.html 上篇帖子: linux小记 -常用命令(三) 下篇帖子: linux动态DNS服务器架设
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表