C语言:extern应用
前面我们都是将所有的代码写到一个源文件里面,对于小程序,代码不过几百行,这或许无可厚非,但当程序膨胀代码到几千行甚至上万行后,就应该考虑将代码分散到多个文件中,否则代码的阅读和维护将成为一件痛苦的事情。
本节我们就来演示一下多文件编程。在下面的例子中,我们创建了两个源文件 main.c 和 module.c:
module.c 是整个程序的一个模块,我们在其中定义了一个全局变量和一个函数;
main.c 是程序的主模块(主文件),它使用到了 module.c 中的变量和函数。
module.c 源码:
#include <stdio.h>
int m = 100;
void func(){
printf("Multiple file programming!\n");
}
main.c 源码:
#include <stdio.h>
extern void func();
extern int m;
int n = 200;
int main(){
func();
printf("m = %d, n = %d\n", m, n);
return 0;
}
在 Visual Studio 中,将两个源文件都添加到工程中,点击“运行(Run)”按钮就可以运行程序。
在 Linux GCC 中,可以使用下面的命令来编译和运行程序:
$gcc main.c module.c
$./a.out
程序最终的运行结果为:
Multiple file programming!
m = 100, n = 200
m 和 n 是在所有函数之外定义的全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的代码文件,包括.c和.h文件。
如果你一直在编写单个源文件的程序,那么请注意,全局变量的作用范围不是从变量定义处到该文件结束,在其他文件中也有效。
这里需要重点理解的是 extern 关键字,它用来声明一个变量或函数。
extern 关键字
我们知道,C语言代码是由上到下依次执行的,不管是变量还是函数,原则上都要先定义再使用,否则就会报错。但在实际开发中,经常会在函数或变量定义之前就使用它们,这个时候就需要提前声明。
所谓声明(Declaration),就是告诉编译器我要使用这个变量或函数,你现在没有找到它的定义不要紧,请不要报错,稍后我会把定义补上。
例如,我们知道使用 printf()、puts()、scanf()、getchar() 等函数要引入 stdio.h 这个头文件,很多初学者认为 stdio.h 中包含了函数定义(也就是函数体),只要有了头文件程序就能运行。其实不然,头文件中包含的都是函数声明,而不是函数定义,函数定义都在系统库中,只有头文件没有系统库在链接时就会报错,程序根本不能运行。
1) 函数的声明
在《C语言函数声明以及函数原型》一节中我们讲到了函数声明,那时并没有使用 extern 关键字,这是因为,函数的定义有函数体,函数的声明没有函数体,编译器很容易区分定义和声明,所以对于函数声明来说,有没有 extern 都是一样的。
总结起来,函数声明有四种形式:
//不使用 extern
datatype function( datatype1 name1, datatype2 name2, ... );
datatype function( datatype1, datatype2, ... );
//使用 extern
extern datatype function( datatype1 name1, datatype2 name2, ... );
extern datatype function( datatype1, datatype2, ... );
2) 变量的声明
变量和函数不同,编译器只能根据 extern 来区分,有 extern 才是声明,没有 extern 就是定义。
变量的定义有两种形式,你可以在定义的同时初始化,也可以不初始化:
datatype name = value;
datatype name;
而变量的声明只有一种形式,就是使用 extern 关键字:
extern datatype name;
另外,变量也可以在声明的同时初始化,格式为:
extern datatype name = value;
这种似是而非的方式是不被推荐的,有的编译器也会给出警告,我们不再深入讨论,也建议各位读者把定义和声明分开,尽量不要这样写。
extern 是“外部”的意思,很多教材讲到,extern 用来声明一个外部(其他文件中)的变量或函数,也就是说,变量或函数的定义在其他文件中。
不过我认为这样讲不妥,因为除了定义在外部,定义在当前文件中也是正确的。例如,将 module.c 中的int m = 100;移动到 main.c 中的任意位置都是可以的。所以我认为,extern 是用来声明的,不管具体的定义是在当前文件内部还是外部,都是正确的。
C语言:extern应用的更多相关文章
- C语言extern作用(全局变量)
用C语言编写程序的时候,我们经常会遇到这样一种情况:希望在头文件中定义一个全局变量,然后包含到两个不同的c文件中,希望这个全局变量能在两个文件中共用. 举例说明:项目文件夹project下有main. ...
- C语言 extern学习2 分析
上一篇文章中,通过头文件声明,而调用有一个特别大的漏洞: 为什么编译器可以链接过来呢,因为默认是extern修饰的,这种类似全局作用域的功能使其可以被调用 继续加强学习: 这一次有两对C文件: fir ...
- C语言extern关键字使用
在chinaunix上看见一篇转载的文章,觉得特别好,关于extern使用的解释: 参考链接:http://doc.chinaunix.net/CPP/201206/2248432.shtml 在C语 ...
- C语言 extern学习1
没有头文件时,通过本文件内的函数声明来确定定义域,实现功能: //单文件测试 #include <stdio.h> /* 经测试,C语言环境下子函数默认是void型:所以可省略不写 为严谨 ...
- 浅谈C语言 extern 指针与数组
/* * d.c * * Created on: Nov 15, 2011 * Author: root */ #include "apue.h" int a[] = {3,2}; ...
- C语言学习及应用笔记之六:C语言extern关键字及其使用
在C语言中,修饰符extern用在变量或者函数的声明前,用来以标识变量或者函数的定义在别的文件中,提示编译器遇到此变量或者函数时,在其它文件中寻找其定义.extern关键字的用法有几种,我们下面对其进 ...
- C++ Primer Plus读书笔记
第五章 循环和关系表达式 1. 2.类别别名: (1) #define FLOAT_POINTER float * FLOAT_POINTER pa, pb; 预处理器置换将该声明转换成 flo ...
- Linux下的动态连接库及其实现机制
Linux与Windows的动态连接库概念相似,但是实现机制不同.它引入了GOT表和PLT表的概念,综合使用了多种重定位项,实现了"浮动代码",达到了更好的共享性能.本文对这些技术 ...
- RT-Thread--内核移植
内核移植 内核移植就是指将 RT-Thread 内核在不同的芯片架构.不同的板卡上运行起来,能够具备线程管理和调度,内存管理,线程间同步和通信.定时器管理等功能.移植可分为 CPU 架构移植和 BSP ...
- 《OOC》笔记(1)——C语言const、static和extern的用法
<OOC>笔记(1)——C语言const.static和extern的用法 C语言中const关键字用法不少,我只喜欢两种用法.一是用于修饰函数形参,二是用于修饰全局变量和局部变量. 用c ...
随机推荐
- GO学习-(7) Go语言基础之流程控制
流程控制是每种编程语言控制逻辑走向和执行次序的重要部分,流程控制可以说是一门语言的"经脉". Go语言中最常用的流程控制有if和for,而switch和goto主要是为了简化代码. ...
- 对端边缘云网络计算模式:透明计算、移动边缘计算、雾计算和Cloudlet
对端边缘云网络计算模式:透明计算.移动边缘计算.雾计算和Cloudlet 概要 将数据发送到云端进行分析是过去几十年的一个突出趋势,推动了云计算成为主流计算范式.然而,物联网时代设备数量和数据流量的急 ...
- Docker_Swarm集群系统
Docker_Swarm集群系统 一.Docker Swarm 介绍 实践中会发现,生产环境中使用单个 Docker 节点是远远不够的,搭建 Docker 集群势在必行.然而,面对 Kubernete ...
- 绘制log()函数图像,并在图上标注选定的两个点
绘制log()函数图像,并在图上标注选定的两个点 import math import matplotlib.pyplot as plt if __name__ == '__main__': x = ...
- Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://dubbo.apache.org/schema/dubbo]
dubbo的官方文档写的真好, http://dubbo.apache.org/zh-cn/docs/2.7/user/dependencies/ 在使用dubbo过程中的问题, 和解决 org.sp ...
- 说说对 Node 中的 fs 模块的理解? 有哪些常用方法?
一.是什么 fs(file system),该模块提供本地文件的读写能力,基本上是POSIX文件操作命令的简单包装 可以说,所有与文件的操作都是通过fs核心模块实现 导入模块如下: const fs ...
- 为什么选择ASP.NET Core
什么是.NET 有一次小飞去面试,面试官上来就问了一个宏观的问题:"你觉得什么是.NET"?小飞的脑子嗡嗡的,支吾了半天,才吐了一些碎片化的词语:"跨平台.开源.微软-& ...
- Spring Boot WebFlux-09——WebFlux 集成测试及部署
第09课:WebFlux 集成测试及部署 前言 在日常工作中,免不了自测 UT,因为覆盖率不达标,是不允许提交测试,那怎么进行 WebFlux 项目的测试呢.@WebFluxTest 是 WebFlu ...
- 魔镜魔镜,今天有雨吗?——GitHub 热点速览 v.21.25
作者:HelloGitHub-小鱼干 上周智能驾驶项目的作者曾经做过一个透明小电视机,同透明电视机类似 MagicMirror 也是一个神奇的智能项目,使用它进行模块定制开发,你将拥有一块非常酷炫的智 ...
- vivo商城促销系统架构设计与实践-概览篇
一.前言 随着商城业务渠道不断扩展,促销玩法不断增多,原商城v2.0架构已经无法满足不断增加的活动玩法,需要进行促销系统的独立建设,与商城解耦,提供纯粹的商城营销活动玩法支撑能力. 我们将分系列来介绍 ...