C语言:全局变量在多个c文件中公用的方法 [转]
用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文件中公用的方法 [转]的更多相关文章
- C#调用其它语言(例如C++)DLL文件中函数的方法摘要
有托管和非托管的概念没仔细看,接下来记录的引用Dll文件指的是无法通过VS自动完成添加引用的情况,可以使用如下方法: 步骤一: 打开“Visual Studio Tools”的“命令提示符”工具 使用 ...
- C++全局变量在多个源代码文件中的使用
在比较大的项目中,如果需要使用全局变量,那么就需要注意一些全局变量声明.使用不当引起的问题了. 本篇文章主要内容有两个:普通全局变量.静态全局变量.全局常量. 1.普通全局变量:假设我们需要在多个不同 ...
- 用户不在sudoers文件中的解决方法
1.更改/etc/sudoers权限为777 2.修改文件中 root ALL=(ALL) ALL 下方增加 user ALL=(ALL) ALL 3.回复文件/e ...
- Mybatis mapper文件中的转义方法
在mybatis中的sql文件中对于大于等于或小于等于是不能直接写?=或者<=的,需要进行转义,目前有两种方式: 1.通过符号转义: 转义字符 < < 小于号 ...
- linux上查找文件存放地点和文件中查找字符串方法
一.查找文件存放地点 1.locate 语法:locate <filename> locate命令实际是"find -name"的另一种写法,但是查找方式跟find不同 ...
- global文件中的application_start方法中做: 定时器
<%@ Application Language="C#" %> <%@ import Namespace="System.Data" %&g ...
- 【java小工具】从.java文件中筛选出方法,并计算出方法在这些文件中出现的次数
package getMethod; import java.io.*; import java.util.*; import java.util.regex.Matcher; import java ...
- vue中js文件中export常见方法及使用
js文件一般放静态资源或动态资源,我将在这两种不同资源的请求下以不同的方式export出来 第一种在js中使用function 动态资源 在vue文件中引用调用这些方法 import进来 在生命周期函 ...
- C语言:字符串读取流读取文件中的数据
#include<stdio.h> int main() { //定义文件指针 FILE *f = NULL; //打开文件 f = fopen("1.txt",&qu ...
随机推荐
- 项目上传svn出问题
我在自己的笔记本上(win8),安装了tortoise 1.9.4和visualSVN server 3.5.3.我现在想让eclipse的自带的svn插件连接到本地服务器的资源库上.但是我写http ...
- 数据结构之Binary Search Tree (Java)
二叉查找树简介 二叉查找树(Binary Search Tree), 也成二叉搜索树.有序二叉树(ordered binary tree).排序二叉树(sorted binary tree), 是指一 ...
- Linux 下安裝 Java SE Development Kit(JDK)並配置環境變量
下載頁面:http://www.oracle.com/technetwork/java/javase/archive-139210.html 打開“Java SE 7”,再打開“Java SE Dev ...
- jquery ColorPicker 颜色选择器
$(function() { $('#colorpickerField').ColorPicker({ onSubmit: function(hsb, hex, rgb, el) { $(el).va ...
- Egret 位图,纹理,添加背景 学习
1,重新设置舞台大小,可以直接到VS中的 "解决方案"中,找到 launcher->egret_loader.js中,找到setDesignSize方法,修改其中大小即可:有 ...
- c# base和this在构造函数中的应用
构造函数可以使用 base 关键字来调用基类的构造函数.例如: public class Manager : Employee{ public Manager(int annualSalary) : ...
- C#中对属性和字段的理解
字段 C#中很少提到全局变量的概念, 引入了字段一词来代替全局变量, 但也并不是这样简单的, 字段会比全局变量的使用更难理解, 使用上会简单, 初学者当做成员变量或者全局变量不会有什么影响, 随着使用 ...
- 又遇Release编译的一坑 -- 应用程序正常初始化(0xc000007b)失败。请单击“确定”,终止应用程序。
项目中使用了xlslib库,以动态库形式编译,由于它没有生成链接库lib文件,所以官方提供的demo中有createDLL这个小程序用来生成lib文件.然而我又 no zuo no die了一次. ...
- Everything(速度快的文件搜索软件) 1.4.1.801b 汉化绿色版
软件名称: Everything(速度快的文件搜索软件) 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win7 / Vista / Win2003 / WinXP 软件大小: 2.0MB ...
- 关于php数组是否要声明
不知道大家有没有这样玩过php数组,正常情况下直接不声明,直接使用数组,会发现输出的与声明后的结果是一样的.