extern——关键字

extern是C语言中的一个关键字,一般用在变量名前或函数名前,作用是用来说明“此变量/函数是在别处定义的,要在此处引用”,extern这个关键字大部分读者应该是在变量的存储类型这一类的内容中

遇到的,下面先分析C语言不同的存储类型

在C语言中变量和函数有数据类型存储类型两个属性,因此变量定义的一般形式为:存储类型 数据类型 变量名表;

C语言提供了一下几种不同的存储类型:

(1)  自动变量(auto)

(2)  静态变量(static)

(3)  外部变量(extern)

(4)  寄存器变量(register)

(上面的auto、static、extern、register都是C语言的关键字),这里只分析extern关键字的使用

外部变量(全局变量)extern----全局静态存储区

标准定义格式:extern 类型名 变量名;

如果在所有函数之外定义的变量没有指定其存储类别,那么它就是一个外部变量,它的作用域是从它的定义点到本文件的末尾(在单个源文件中的确是这样,如果有多个源文件,全局变量的作用范围不是从变量定义处到该文件结尾,而是在其他文件中也有效),但是如果要在定义点之前或者其他文件中使用它,那么就需要使用关键字extern对其进行声明(注意不是定义,编译器并不为其分配内存)

Tips:

定义:表示创建变量或分配存储单元

声明:说明变量的性质,但并不分配存储单元

extern int i; //是声明,不是定义,没有分配内存
int i; //是定义

如果在声明的时候给变量赋值,那么就和去掉extern直接定义变量赋值是等价的

extern int a = ;//尽量不要写这种定义方式
int a = ;//上述两条语句等价

(注意上面的不同语句对声明和定义的区分,对源文件中的局部变量来说是成立的(也就是.c文件),而对于源文件中的全局变量(外部变量)int a和在头文件中的int a就不能用上面的语句来解释声明和定义的区别)

补充:定义和声明的一个小坑,对于int a;来说,在源文件中,如果是全局变量的话就是声明,如果是局部变量的话就是定义

全局变量:

文章前面提到过一句话:如果在所有函数之外定义的变量没有指定其存储类别,那么它就是一个外部变量,意思就是这里的int a;等价于extern int a;相当于声明,声明是可以多次的

局部变量:

文章中只提到了extern(外部变量),这里补充下auto(自动变量),由于auto(自动变量)极为常用,所以C语言把它设计成缺省的存储类型,即auto 可以省略不写,在main函数内部的变量int a也是局部变量,

相当于auto int a;相当于定义,定义只能一次

谨记:声明可以多次,定义只能一次

外部变量保存在静态存储区内,在程序运行期间分配固定的存储单元,其生存期是整个程序的运行期,没有显式初始化的外部变量由编译程序自动初始化为0(extern说明符来扩展全局变量的作用域,

可以将全局变量的作用域扩展到其他文件,但不能限制全局变量的作用域

extern作用于函数名和变量名时的区别:

读者应该会发现,函数声明时并没有使用 extern 关键字,这是因为,函数的定义有函数体,函数的声明没有函数体,编译器很容易区分定义和声明,所以对于函数声明来说,有没有extern 都是一样的

但是作用于变量名时extern关键字就不是可有可无的了,全局变量在外部使用声明时,extern关键词是必须的,如果变量无extern修饰且没有显式的初始化,就成为了变量的定义,因此此时必须加extern,

全局变量在不指定初值时会自动初始化为0

多文件编程

C语言代码是由上到下依次执行的,不管是变量还是函数,原则上都要先定义再使用,否则就会报错。但在实际开发中,经常会在函数或变量定义之前就使用它们,这个时候就需要提前声明(extern)

头文件中包含的都是函数声明,而不是函数定义

最好不要在头文件中定义变量,例如全局变量

这里的int a是个全局变量的定义,所以如果这个头文件被多次引用的话,a会被重复定义,这显然是不允许的,下面举一个简单多文件编程的例子

从上面的四张图可以看出,一共用了3个文件,两个c文件(源文件)一个h文件(头文件),我在my.c中写了一个函数名为Max的函数,在头文件中声明了这个Max函数,在有main的这个test1.c这个

源文件中用#include "my.h"包含了这个头文件,然后在函数中就可以直接使用Max函数了(注意头文件中只是声明,没有定义,而且不建议在头文件中定义函数,会引起很多不必要的麻烦

在《高质量C/C++编程指南》一书中,对此也有说明:

【建议1-2-1】头文件中只存放“声明”,而不存放“定义”。

在C++语法中,类的成员函数可以在声明的同时被定义,并且自动成为内联函数。这虽然会带来书写上的方便,但却造成了风格不一致,弊大于利。建议将成员函数的定义分开,不论该函数体有多么小。

【建议1-2-2】不提倡使用全局变量,尽量不要在头文件中出现现象 extern int value 这类声明。

作者:奄奄不息 
原文:https://blog.csdn.net/qq_41209741/article/details/84108962 

问题一:如果在my.c这个文件中定义了一个全局变量,想要在main函数中使用,该怎么做呢?

方法一:在含有main函数的源文件test1.c中加extern声明

运行结果:

方法二:在头文件中my.h中对my.c中的全局变量进行声明,再在test1.c中include头文件my.h

运行结果:

防止C语言头文件被重复包含

头文件包含命令 #include 的效果与直接复制粘贴头文件内容的效果是一样的,预处理器实际上也是这样做的,它会读取头文件的内容,然后输出到 #include 命令所在的位置,头文件包含是一个

递归(循环)的过程,如果被包含的头文件中还包含了其他的头文件,预处理器会继续将它们也包含进来;这个过程会一直持续下去,直到不再包含任何头文件,这与递归的过程颇为相似,

递归包含会导致一个问题,就是重复引入同一个头文件,重复引入同一头文件有什么问题呢,当你在头文件中定义变量或者函数时(注意是定义不是声明,多次声明是没有问题的)多次引入头文件就会报“变量被多次定义”的错误

下面来还原这种错误:

上面一共使用了3个头文件k1.h、k2.h、my.h在k1.h和k2.h中都包含了my.h,而且在my.h中有一个全局变量int k = 10,在test1.c中包含了上述三个头文件

编译结果

解决方法:

方法一:使用条件编译#ifndef(如果读者对条件编译不了解,可以先看一下这一篇随笔预处理命令使用详解----#if、#endif、#undef、#ifdef、#else、#elif

解释一下上面的条件编译语句,如果_MY_H这个宏名没有被定义,那么定义_MY_H这个宏名,并且定义全局变量int k = 10,这样做就避免了头文件的重复包含引起的,变量或函数的重复定义问题

我们可以在stdio.h这个“标准输入\输出头文件”中看到类似的用法

格式就像下面这个样子:

#ifndef _INC_STDIO
#define _INC_STDIO
/* 头文件内容 */
#endif

这种宏保护方案使得程序员可以“任性”地引入当前模块需要的所有头文件,不用操心这些头文件中是否包含了其他的头文件

但也不是没有缺点

#ifndef的方式依赖于宏名不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含

缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况

方法二:使用#pragma once

#pramgma once是微软编译器独有的,也是后来才有的,所以知道的人并不是很多,用的人也不是很多,因为他不支持跨平台。如果你想写跨平台的代码,最好使用条件编译,如果想使用#pragma once,

只需在头文件开头加上#pragma once即可

#pragma带来的好处是:你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题,坏处也有,#pragma once是由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件,如果某个头文件有多份拷贝,这个方法就不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正

总结:1.#ifndef 由语言支持所以移植性好

    2.#pragma 可以避免名字冲突 

extern的使用详解(多文件编程)——C语言的更多相关文章

  1. ZT --- extern "C"用法详解 2010-08-21 19:14:12

    extern "C"用法详解 2010-08-21 19:14:12 分类: C/C++ 1.前言: 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus ...

  2. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  3. MFC中文件对话框类CFileDialog详解及文件过滤器说明

    当前位置 : 首页 » 文章分类 :  开发  »  MFC中文件对话框类CFileDialog详解及文件过滤器说明 上一篇 利用OpenCV从摄像头获得图像的坐标原点是在左下角 下一篇 Word中为 ...

  4. 一阶RC高通滤波器详解(仿真+matlab+C语言实现)

    文章目录 预备知识 关于电容 HPF的推导 simulink 仿真 simulink 运行结果 matlab 实现 matlab 运行结果 C语言实现 如果本文帮到了你,帮忙点个赞: 如果本文帮到了你 ...

  5. 一阶RC低通滤波器详解(仿真+matlab+C语言实现)

    文章目录 1 预备知识 2 simulink 仿真 3 simulink 运行结果 4 matlab实现 5 matlab运行结果 6 C语言实现 7 C语言运行结果 如果本文帮到了你,帮忙点个赞: ...

  6. Socket详解-Linux Socket编程(不限Linux)

    “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...

  7. extern extern “C”用法详解

    1.extern 修饰一个变量,告诉编译器这个变量在其他地方定义,编译器不会给出变量未定义的警告. extern tells the compiler that the variable is def ...

  8. ***PHP $_FILES函数详解 + PHP文件上传 move_uploaded_file() 参数的正确写法

    PHP $_FILES函数详解 在PHP中上传一个文件建一个表单要比ASP中灵活得多.具体的看代码. 如:  复制代码代码如下: <form enctype="multipart/fo ...

  9. hadoop2.7作业提交详解之文件分片

    在前面一篇文章中(hadoop2.7之作业提交详解(上))中涉及到文件的分片. JobSubmitter.submitJobInternal方法中调用了int maps = writeSplits(j ...

随机推荐

  1. 获取电脑的 SN 码

    wmic bios get serialnumber

  2. 1安装Linux

    第二天笔记打卡. 系统安装注意:1.DATE&TIME2.Server with GUI3.分区默认4.网络开启 源代码安装:1.安装难度高2.编译环境复杂3.解决依赖关系 源代码:2.部署编 ...

  3. byobu 禁止窗口名称随目录变化

    It looks like the config set-window-option -g automatic-rename off doesn't work. When I added the fo ...

  4. spring-AOP之通知和顾问

    通知和顾问都是切面的实现形式,其中通知可以完成对目标对象方法简单的织入功能. 而顾问包装了通知,可以让我们对通知实现更加精细化的管理,让我们可以指定具体的切入点. 通知分为前置通知,环绕通知及后置通知 ...

  5. JAVA字符串类

    一.字符串类String1.String是一个类,位于java.lang包中2.创建一个字符串对象的2种方式: String 变量名=“值”; String 对象名=new String(“值”);3 ...

  6. Linux学习-linux系统下安装jdk和tomcat,以及遇到的问题清单

    安装JDK 1. 在usr目录下建立java安装目录 cd /usr mkdir java   2.下载jdk包 登录网址:http://www.oracle.com/technetwork/java ...

  7. cdnbest里如何查看网站是否被缓存

    比如开启了强制缓存,如何查看缓存是否生效 本例以firefox浏览器查看,先打开浏览器,按下F12, 然后在浏览器是输入网址访问 如下图响应头里的 x-cache显示 Miss  from 就是没有缓 ...

  8. 49-2015年第6届蓝桥杯Java B组

    1.三角形面积 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文字.   image.png   计算方法: 8 * ...

  9. PHP pthread 多线程 案例

    <?php /** *检测http服务是否可以正常访问 *启动三个线程执行任务 */ class taskWork extends Thread { public $url = ''; //检测 ...

  10. centos7 下安装pycharm

    CentOS 7环境下Pycharm安装流程记录: 1.准备安装文件: 方法1: 使用内置火狐浏览器访问下载最新格式为tar.gz的压缩包 网址:https://www.jetbrains.com/p ...