15-static和extern关键字1-对函数的作用

时间:2021-07-07 23:55:38

一、extern与函数

如果一个程序中有多个源文件(.c),编译成功会生成对应的多个目标文件(.obj),这些目标文件还不能单独运行,因为这些目标文件之间可能会有关联,比如a.obj可能会调用c.obj中定义的一个函数。将这些相关联的目标文件链接在一起后才能生成可执行文件。

先来理解2个概念:

  • 外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数。C语言规定,不允许有同名的外部函数。
  • 内部函数:如果在当前文件中定义的函数不允许其他文件访问、调用,只能在内部使用,就称为内部函数。C语言规定不同的源文件可以有同名的内部函数,并且互不干扰。

接下来就演示在一个源文件中调用另外一个源文件定义的函数,比如在main.c中调用one.c中定义的one函数。

1.首先在one.c中定义了一个one函数

如果你想让这个one函数可以被main.c访问,那么one函数就必须是外部函数。完整的定义是要加上extern关键字。

15-static和extern关键字1-对函数的作用

不过这个extern跟auto关键字一样废,完全可以省略,因为默认情况下,所有的函数就是外部函数。我们可以简化一下:

15-static和extern关键字1-对函数的作用

2.接下来,我想在main.c的main函数中,调用one.c中的one函数

15-static和extern关键字1-对函数的作用

怎样才能调用one.c中的one函数呢?你可能会产生2个想法:

想法1:直接在main函数中写上one();

15-static和extern关键字1-对函数的作用

这个做法肯定不行,因为main函数根本不知道one函数的存在,怎么调用呢?这个在标准C编译器里面会报错的,但是在Xcode中只是个警告。

想法2:在main.c中包含one.c文件

15-static和extern关键字1-对函数的作用

大家都知道#include的作用纯粹就是内容拷贝,所以又相当于

15-static和extern关键字1-对函数的作用

哎,这么一看好像是对的哦,在main函数前面定义了个one函数,然后在main函数中调用了这个one函数。从语法上看是对的,所以编译是没问题的。但是这个程序不可能运行成功,因为在链接的时候会报错。我们已经在one.c中定义了one函数,现在又在main.c中定义one函数,C语言规定不允许有同名的外部函数,链接的时候链接器会发现在one.obj和main.obj中定义了同一个函数,会直接报错,Xcode中的错误信息是这样的:

15-static和extern关键字1-对函数的作用

duplicate symbol _one是说one这个标识符重复了,linker是指链接器。

上面的2种想法都是不可行的,其实思路是一致的:让main函数知道one函数的存在。正确的做法应该是在main函数前面对one函数进行提前声明(看清楚,是声明,不是定义,定义和声明是两码事)。

3.在main函数前面对one函数进行提前声明

你想要把其他源文件中定义的外部函数拿过来声明,完整的做法,应该使用extern关键字,表示引用别人的"外部函数"

15-static和extern关键字1-对函数的作用

运行程序,从控制台输出可以发现 "one.c中定义的one函数" 已经被 "main.c的main函数" 成功调用了。

也有人可能会马上冒出一个想法:假如除开one.c,还有其他源文件也有定义这个one函数怎么办?那main函数调用的究竟是谁的one函数啊?放心,绝对不会有这种情况,刚才不是说了么,不允许重复定义同一个外部函数,不然链接器会报错的,所以只会有一个外部one函数。

上述就是extern关键字对函数的作用:用来定义和声明一个外部函数。其实extern又跟auto一样废,完全可以省略。于是,我们可以简化成这样:

15-static和extern关键字1-对函数的作用

 

二、static与函数

1.定义内部函数

从上面的例子可以看出,one.c中定义的one函数是可以被其他源文件访问的。其实有时候,我们可能想定义一个"内部函数",也就是不想让其他文件访问本文件中定义的函数。这个非常简单,你只需要在定义函数的时候加个static关键字即可。

(我们就在上面例子的代码基础上进行修改)

15-static和extern关键字1-对函数的作用

我在void one()的前面加了个static,代表one函数是个内部函数。

然后你会发现程序运行不起来了,在链接的时候就报错了。报错的原因很简单:我们在main.c中调用了one.c中定义的one函数,但是现在one.c的one函数是个"内部函数",不允许其他文件访问。我们来看看错误信息:

15-static和extern关键字1-对函数的作用

第1个红框中的Undefined symbols...意思是one这个标识符没有被定义,也就是找不到one;第2个红框的linker表明是链接器报错了。

但这个程序是可以编译成功的,因为我们在main函数前面声明了one函数(函数的声明和定义是两码事),这个函数声明可以理解为:在语法上,骗一下main函数,告诉它one函数是存在的,所以从语法的角度上main函数是可以调用one函数的。究竟这个one函数存不存在呢,有没有被定义呢?编译器是不管的。在编译阶段,编译器只会检测单个源文件的语法合不合理,并不检测函数有没有定义,只有在链接的时候才会检测这个函数存不存在,也就是有没有被定义。

15-static和extern关键字1-对函数的作用  15-static和extern关键字1-对函数的作用

我们再来讨论一个问题,为什么好多情况下都是可以成功编译,但是链接的时候报错呢?只要你理解编译和链接的作用就好办了。

所谓编译,就是单独检查每个源文件的语法是否合理,并不会检查每个源文件之间的关联关系,一个源文件编译成功就生成一个目标文件。

所谓链接,就是检查目标文件的关联关系,将相关联的目标文件组合在一起,生成可执行文件。

看完这2个概念,再回去思考下前面报的错,应该可以完全明白了。

2.声明内部函数

我们还可以用static声明一个内部函数

15-static和extern关键字1-对函数的作用
 1 #include <stdio.h>
2
3 static void test();
4
5 int main(int argc, const char * argv[])
6 {
7 test();
8 return 0;
9 }
10
11 static void test() {
12 printf("调用了test函数");
13 }
15-static和extern关键字1-对函数的作用

在第11行定义了一个test函数,这是一个内部函数,接着在第3行对test函数进行提前声明,然后就可以在第7行可以调用test()函数了

三、static、extern与函数的总结

1.static

* 在定义函数时,在函数的最左边加上static可以把该函数声明为内部函数(又叫静态函数),这样该函数就只能在其定义所在的文件中使用。如果在不同的文件中有同名的内部函数,则互不干扰。

* static也可以用来声明一个内部函数

2.extern

* 在定义函数时,如果在函数的最左边加上关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。

* 在一个文件中要调用其他文件中的外部函数,则需要在当前文件中用extern声明该外部函数,然后就可以使用,这里的extern也可以省略。

15-static和extern关键字1-对函数的作用的更多相关文章

  1. C语言中:static与extern对变量和函数的作用

    1.两者对全局变量 static对全局变量,表示定义一个内部变量 extern对全局变量,表示声明一个外部变量 说明: 1.内部变量:定义的变量只能在本文件中访问,不能被其他文件访问. 2.不同文件中 ...

  2. 转载 浅谈C&sol;C&plus;&plus;中的static和extern关键字

    浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T   static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...

  3. static 和extern关键字

    static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话 ...

  4. 浅谈C&sol;C&plus;&plus;中的static和extern关键字

    static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话 ...

  5. static和extern关键字 对函数的作用

    本文目录 • 一.extern与函数 • 二.static与函数 • 三.static.extern与函数的总结说明:这个C语言专题,是学习iOS开发的前奏.也为了让有面向对象语言开发经验的程序员,能 ...

  6. 16-static和extern关键字2-对变量的作用

    上一讲介绍了static和extern对函数的作用,static用来定义一个内部函数,不允许其他文件访问:extern用来定义和声明一个外部函数,允许其他文件访问.static和extern对变量也有 ...

  7. 浅谈C&sol;C&plus;&plus;中的static和extern关键字 转

    原文:http://developer.51cto.com/art/201104/256820.htm static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.extern, &quo ...

  8. C语言的static和extern关键字

    我的博客:www.while0.com 如果A.c要包含B.c里的一个变量或函数,则在A.c中要用extern关键字声明.注意: ①如果是包含的B.c里的函数,则在A.c里声明的时候可以不写exter ...

  9. static和extern关键字 对变量的作用

    本文目录 • 一.在Java中,全局变量的定义没有严格的位置规定 • 二.在C语言中,全局变量定义的位置是有限制的 • 三.重复定义同一个变量 • 四.不同源文件中的同名变量 • 五.static关键 ...

随机推荐

  1. Dictionary Learning&lpar;字典学习、稀疏表示以及其他&rpar;

    第一部分 字典学习以及稀疏表示的概要 字典学习(Dictionary Learning)和稀疏表示(Sparse Representation)在学术界的正式称谓应该是稀疏字典学习(Sparse Di ...

  2. 50个C&sol;C&plus;&plus;源代码网站

    C/C++是最主要的编程语言.这里列出了50名优秀网站和网页清单,这些网站提供c/c++源代码 .这份清单提供了源代码的链接以及它们的小说明.我已尽力包括最佳的C/C++源代码的网站.这不是一个完整的 ...

  3. HTTP POST GET 本质区别详解

    HTTP POST GET 本质区别详解 一 原理区别 一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认为GET提交 Ht ...

  4. bzoj 3223&sol;tyvj 1729 文艺平衡树 splay tree

    原题链接:http://www.tyvj.cn/p/1729 这道题以前用c语言写的splay tree水过了.. 现在接触了c++重写一遍... 只涉及区间翻转,由于没有删除操作故不带垃圾回收,具体 ...

  5. 使用php代码如何筛选出ie6及以下的浏览器。

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-04-09) <?php //ie6及以下的浏览器不加载js_menu文件. if (strpos($_SERVER[' ...

  6. 关于一次Weblogic活动线程的问题处理

    Weblogic控制台监控发现 环境>>服务器>>你的服务器>>监控>>线程 中活动执行线程竟然是2000多.同一套系统在另一套平台上,并且访问的人不少 ...

  7. &lbrack;SDOI2009&rsqb;学校食堂Dining

    题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数 ...

  8. Ural 1966 Cycling Roads

    ================ Cycling Roads ================   Description When Vova was in Shenzhen, he rented a ...

  9. IntelliJ IDEA如何设置新建类时,自动注释作者信息和日期时间

    本文提供两种注释风格供参考. 风格1:简约Style 效果如下: 设置步骤: File--> Settings--> Editor--> File and Code Template ...

  10. dns与wins的区别

    将主机名字解析称为ip地址有四种办法: dns.winds.hosts文件.lmhosts文件 dns和hosts是很多系统cout采用的一个名称解析的方法,wins和lmhosts是微软的操作系统此 ...