用C语言编写程序的时候,我们经常会遇到这样一种情况:希望在头文件中定义一个全局变量,然后包含到两个不同的c文件中,希望这个全局变量能在两个文件中共用

  举例说明:项目文件夹project下有main.c、common.c和common.h三个文件,其中common.h文件分别#include在main.c和common.c文件中。现在希望声明一个字符型变量key,在main.c和common.c中公用。如下图所示:

有人想,既然是想两个文件都用,那就在common.h中声明一个unsigned char key,然后由于包含关系,在main.c和common.c中都是可见的,所以就能共用了。

这种想法其实是很多初学者都会想到的,想起来确实有道理,但是实际写出来,我们发现编译的时候编译器提示出错,一般提示大概都类似于:Error: L6200E: Symbol key multiply defined (by common.o and main.o). 也就是说编译器认为我们重复定义了key这个变量。这是因为#include命令就是原封不同的把头文件中的内容搬到#include的位置,所以相当于main.c和common.c中都执行了一次unsigned char key,而C语言中全局变量是项目内(或者叫工程内)可见的,这样就造成了一个项目中两个变量key,编译器就认为是重复定义。

  正确的解决办法:使用extern关键字来声明变量为外部变量。具体说就是在其中一个c文件中定义一个全局变量key,然后在另一个要使用key这个变量的c文件中使用extern关键字声明一次,说明这个变量为外部变量,是在其他的c文件中定义的全局变量。请注意我这里的用词:定义声明。例如在main.c文件中定义变量key,在common.c文件中声明key变量为外部变量,这样这两个文件中就能共享这个变量key了,如下图所示。

代码如下(只写跟我们所说问题有关的部分):

  (1)main.c文件

 #include "common.h"
  unsigned char key;

  (2)common.c文件:

 #include "common.h"
  extern unsigned char key;

  很多人看了可能糊涂,这里稍微说一下,其实就是变量定义变量声明的区别,变量定义使用“数据类型+变量名称”的形式,编译器需要给他分配内存单元的;而变量声明使用“extern 变量类型+变量名称”的形式,是告诉编译器我这个变量将在其他外部c文件中定义,我这里只是在外部用它。编译器就不给他分配内存空间,而等到真正遇到变量定义的时候再给他分配内存空间。

  由于很多人从开始学C语言就一直把定义变量声明变量,一开始就叫错了,所以导致现在分不清定义声明的区别。要是还理解不了就想想函数的定义声明,函数定义是编写函数功能实体,编译器要编译这个函数并且要分配内存空间,而函数声明并不生成函数功能实体,只是告诉编译器这是个函数,这个函数在后面将会定义实体,我这里只是提前用,编译器就会接着继续往下编译,如果子函数写在main函数之后,那么声明是必须的,如果不声明函数编译器都不知道这是个函数,编译就会报错。

  说了这么多应该说明白了,如果还有问题可以参考谭浩强的那本C语言书,书中有详细解释和例子。

C语言:全局变量在多个c文件中公用的方法 [转]的更多相关文章

  1. C#调用其它语言(例如C++)DLL文件中函数的方法摘要

    有托管和非托管的概念没仔细看,接下来记录的引用Dll文件指的是无法通过VS自动完成添加引用的情况,可以使用如下方法: 步骤一: 打开“Visual Studio Tools”的“命令提示符”工具 使用 ...

  2. C++全局变量在多个源代码文件中的使用

    在比较大的项目中,如果需要使用全局变量,那么就需要注意一些全局变量声明.使用不当引起的问题了. 本篇文章主要内容有两个:普通全局变量.静态全局变量.全局常量. 1.普通全局变量:假设我们需要在多个不同 ...

  3. 用户不在sudoers文件中的解决方法

    1.更改/etc/sudoers权限为777 2.修改文件中 root    ALL=(ALL)       ALL 下方增加 user    ALL=(ALL)       ALL 3.回复文件/e ...

  4. Mybatis mapper文件中的转义方法

    在mybatis中的sql文件中对于大于等于或小于等于是不能直接写?=或者<=的,需要进行转义,目前有两种方式: 1.通过符号转义: 转义字符       <     <   小于号 ...

  5. linux上查找文件存放地点和文件中查找字符串方法

    一.查找文件存放地点 1.locate 语法:locate <filename> locate命令实际是"find -name"的另一种写法,但是查找方式跟find不同 ...

  6. global文件中的application_start方法中做: 定时器

    <%@ Application Language="C#" %> <%@ import Namespace="System.Data" %&g ...

  7. 【java小工具】从.java文件中筛选出方法,并计算出方法在这些文件中出现的次数

    package getMethod; import java.io.*; import java.util.*; import java.util.regex.Matcher; import java ...

  8. vue中js文件中export常见方法及使用

    js文件一般放静态资源或动态资源,我将在这两种不同资源的请求下以不同的方式export出来 第一种在js中使用function 动态资源 在vue文件中引用调用这些方法 import进来 在生命周期函 ...

  9. C语言:字符串读取流读取文件中的数据

    #include<stdio.h> int main() { //定义文件指针 FILE *f = NULL; //打开文件 f = fopen("1.txt",&qu ...

随机推荐

  1. CodeForces 631D Messenger

    $KMP$. $n=1$和$n=2$的时候可以单独计算.$n>2$时,可以拿字符和数字分别做一次匹配,然后扫描一遍判断一下就可以计算出答案了. #pragma comment(linker, & ...

  2. [HMLY]14.对iOS开发中使用MVVM的理解和使用(初级)

    前言 MVVMDemo 之前几个月一直在学习react-native,它的组件化开发真的是很棒,控件和页面的组件化在开发中可以很好的复用,节省开发时间.在那个时候还不知道react-native开发用 ...

  3. Cocos2d-x 3.x事件分发机制总结

    在2.x中处理事件需要用到委托代理(delegate),相信学过2.x的触摸事件的同学,都知道创建和移除的流程十分繁琐.而在3.x中由于加入了C++11的特性,而对事件的分发机制通过事件分发器Even ...

  4. android中edittext被键盘挡住问题

    最近开始新项目,做注册页时候由于ui布局问题,edittext被键盘挡住了. 在stackoverflow上找了一遍,有提到在对应activity中设置windowSoftInputMode, 例如: ...

  5. shell 文件中列的整合成一个文件

    原文件 第一种方法 [root@wxb- jt]# paste -d "," b c d ,q, , ,e, ,r, ,t, [root@wxb- jt]# paste b c d ...

  6. attr 和 prop 区别

    jquery 中 attr 和 prop 都表示 "属性",同样是属性为啥还要弄两个! attr 适用于自定义属性 如 定义一个懒加载用的src 栗子 <img class= ...

  7. CODE[VS]-最小数和最大数-整数处理-天梯青铜

    题目描述 Description 输入n个数,n<=100,找到其中最小的数和最大的数 输入描述 Input Description 第一行一个整数n 接下来一行n个整数,每个整数不超过231 ...

  8. 在ueditor编辑器的光标停留处插入内容

    业务场景: 首先在ueditor编辑器中插入一段文本,然后我想在文本的某个位置(光标停留处)插入一个字符串,这个字符串是从页面的其他地方选择得来的. 注意,当我们点击ueditor编辑器以外的地方,编 ...

  9. JQuery-常用小组件

    常用的小组件记录 1. 单选框.复选框重置样式效果 参考: http://www.cnblogs.com/sanshi/p/4369375.html 三生石上 参考: http://www.jq22. ...

  10. 关于ios原声嵌入web页面的问题

    当在一个界面中既有原生又有web的时候,如果想让上下整体滑动的话,我们怎么确定web的高度呢,下面分享一下我的心得 首先在webView的代理方法中我们可以获取到加载完整个web页面的高度 - (vo ...