C语言——全局变量的定义与声明

2023-05-16

转自:

https://www.cnblogs.com/amanlikethis/p/3319744.html 

 

C语言中全局变量的定义与声明困扰着许多C语言初学者。本文讲述了全局变量定义与声明的用法,而且本为也将阐述这种用法的内在原理。我们先从两个错误例子引入,以下两个例程都在vc6.0平台上测试。

两种错误例程

1.unresolved external symbol

例子包含两个C文件(test.c)和(first.c)和一个头文件(test.h)。下边具体展示下它们的代码。

test.h内容

#ifndef _TEST_H
#define _TEST_H
 
extern int count;   

#endif

test.c内容

#include <stdio.h>
#include "test.h"
extern void Fis_Cal(void);
void main(void)
{
 Fis_Cal();
  printf("the present value of count is %d\n",count);
}

first.c内容

#include <stdio.h>
#include "test.h"
void Fis_Cal(void)
{
 printf("the last value of count is %d\n",count);
 count = 1;
}

错误分析:test.h头文件中声明了全局变量count,但是在两个C文件中都没有对count进行定义,所以才会出现unresolved external symbol。

一种解决方法:随便在两个C文件中加入一句“int count;”就OK了。例如我们加到test.c中,代码如下。 

#include <stdio.h>
#include "test.h"
extern void Fis_Cal(void);
int count;
void main(void)
{
 Fis_Cal();
 printf("the present value of count is %d\n",count);
}

说明:加入的“int count;”就是对count的定义,默认的将其初始化为0。

结论:这种错误原因是“只声明未定义”。

2.multiply defined symbols found

还是如此,三个文件。但是,两个C文件与例程一中的文件一样,改动的只是头文件。

test.h内容

#ifndef _TEST_H
#define _TEST_H
 
int count; 

#endif

可以看到,与例程一仅仅差了一个“extern”关键词。

错误分析:test.h头文件中定义了全局变量count,但是在两个C文件都通过“#include "test.h"”这句话对“int count;”进行了引用,所以造成了重复定义的错误。

一种解决方法:添加一个“first.h”的头文件,并且更改first.c的内容,具体更改如下。

first.h内容

#ifndef _FIRST_H
#define _FIRST_H

extern int count;

#endif

first.c内容

#include <stdio.h>
#include "first.h"
void Fis_Cal(void)
{
 printf("the last value of count is %d\n",count);
 count = 1;
}

说明:经过这样的修改,原来的test.c中就包含了count的定义,而first.c中就包含了对count的声明,重复定义错误就得到解决。

结论:这种错误原因是“多个C程序都包含了定义全局变量的头文件”。 

原理分析

    我认为“int count;”是对全局变量的定义,而“extern int count”是对全局变量的声明,目的是让其他文件也使用这个全局变量。下边我们来挖掘全局变量的定义与声明的内涵。

    全局变量要么初始化(非零),要么没有初始化(为零)。非零时存储在程序中的data段,零时存储在程序的bss段。这谈了程序(.bin或者.hex)的结构。我再讲一下程序的启动,程序在启动(boot)过程中,通常都会运行一个叫bootloader的引导程序,这个引导程序干了很多事情,其中有一最重要的任务就是把程序(test段和rodata段)拷贝到内存,还包括data段的拷贝和bss段初始化。我们着重讲一下data段的拷贝和bss段初始化。

    我们的编译器会为我们定义的全局变量分配内存(地址),而且给我们的全局变量赋初值(写内存或清零),以后我们的程序就会根据需要来读这个全局变量(地址)或者修改这个全局变量(写内存)。初值为零时就在bss段,这个段初始化代码会将这部分清零。初值非零时,初始化代码会将全局变量的初值拷贝到data段。

    那么,显然全局变量的初值只有一个。我们程序中的全局变量的定义就是对全局变量分配内存并赋初值。而全局变量的声明是为了跨文件使用全局变量的需要,通过"extern"关键词来将全局变量引出。 

顺便说一下C语言的存储类说明符,这能帮助我们加深理解。

C语言的存储类说明符

     Auto 只在块内变量声明中被允许, 表示变量具有本地生存期。

     Extern 出现在顶层或块的外部变量函数与变量声明中,表示声明的对象具有静态生存期, 连接程序知道其名字。

    Static 可以放在函数与变量声明中,在函数定义时,只用于指定函数名,而不将函数导出到链接程序,在函数声明中,表示其后边会有定义声明的函数,存储类型static.在数据声明中,总是表示定义的声明不导出到连接程序关键字。

一种更好的声明与定义方式

test.h内容 

#ifndef _TEST_H
#define _TEST_H
 
#ifdef GLOBALS
int count;
#else
extern int count;
#endif 

#endif

test.c内容

#define GLOBALS
#include <stdio.h>
#include "test.h"
extern void Fis_Cal(void);
void main(void)
{
 Fis_Cal();
 printf("the present value of count is %d\n",count);
}

first.c内容

#include <stdio.h>
#include "test.h"
void Fis_Cal(void)
{
 printf("the last value of count is %d\n",count);
 count = 1;
}

说明:这种方法可以只定义一个头文件实现在不同C文件中分别实现定义与声明。“#define GLOBALS”只在当前定义的test.c文件中有效,所以在test.c中#include "test.h"预处理后,加入的是int count,而first.c中加入的"extern int count;"。其实还有一种书写方法,也能实现这个效果。

test.h内容 

#ifndef _TEST_H
#define _TEST_H
 
#ifdef GLOBALS
#define EXT
#else
#define EXT extern
#endif

EXT int count;

#endif

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言——全局变量的定义与声明 的相关文章

  • CompletableFuture使用示例

    不进行异常处理 1 runAsync 无返回值 supplyAsync 有返回值 根据idea的提示和变量的范型也能看出来 runAsync 是不返回值的 而supplyAsync则会把比较的结果返回出去 2 thenApply thenA
  • 《Linux驱动:USB设备驱动看这一篇就够了》

    文章目录 一 xff0c 前言二 xff0c USB子系统2 1 USB驱动基础概念2 1 1 USB版本2 1 2 USB主从结构2 1 3 USB的传输类型2 1 4 USB设备描述符2 1 4 1 设备描述符2 1 4 2 配置描述符
  • ModbusPoll和ModbusSlave理解及模拟器ModbusTcp一对一和一对多通讯

    目录 ModbusPoll和ModbusSlave理解 Modbus总概 xff1a 主从区分 xff1a 模拟器简介 xff1a ModbusTcp一对一通讯 ModbusTcp一对多通讯 ModbusPoll和ModbusSlave理解
  • SpringSecurity关于关闭csrf后导致页面元素消失的问题及处理方法

    在学习SpringSecurity时进行自定义登录页面的编写时 xff0c 由于在学习的过程中暂时用不到csrf防护 xff0c 不关闭的话后面可能会因为没考虑csrf防护而遇到一连串的问题 xff0c 且关闭后直接使用GET请求也可以退出
  • 机器人开发ros初识

    首先 xff0c 采用ros系统的机器人一般都是有上位机和下位机的 xff0c 下位机以arduino为例 xff0c 负责订阅上位机发送的topic xff0c 获取信息后通过设计的代码进行相应处理控制硬件 xff0c 比如移动 xff0
  • 使用Python+requests简单实现模拟登录以及抓取接口数据

    前言 xff1a 说起爬虫这个东西 xff0c 大学时我习惯用PHP 43 CURL来实现 xff0c 后来用Java 43 WebMagic来实现 如今刚接触一下Python xff0c 开始了解一下Python的语法和框架等 xff0c
  • 常用数据集网盘免费下载(转载)

    List item 遥感影像库 链接 xff1a https pan baidu com s 1bGLRZo 密码 xff1a ic0t facebook大数据 链接 xff1a https pan baidu com s 1geGBLb9
  • C++连接MySQL 操作的封装

    以前写过一篇 c 43 43 连接mysql 的博客 xff0c 每次都要写类来封装数据库的操作函数 xff0c 参考一位大佬的封装 xff0c 不说了 xff0c 直接上代码 xff1a 头文件如下 xff1a pragma once i
  • C++11 线程池的使用

    本文主要介绍C 43 43 中线程池的实现以及C 43 43 11中新特性 仿函数 线程 互斥量 原子 条件变量等 的使用 xff0c 最终会实现一个简易的线程池 xff0c 可支持传参不传参等任务 目录 一 线程池的用途 1 线程池的作用
  • ubuntu 首次安装后配置开发环境

    目录 1 配置root 密码 2 安装SSH 3 安装网络 4 安装和配置 vim 5 配置C 43 43 开发环境 6 安装代码管理工具 git 6 1 配置邮箱和用户名 7 多用户与图形界面切换 1 配置root 密码 sudo pas
  • window11 无法切换输入法打印不出汉字问题修改

    1 xff09 按 WINDOW 43 R 键启动cmd 窗口 2 xff09 在cmd窗口中输入 services msc 启动服务窗口 3 xff09 找到 TextInputManagementService xff0c 开启即可
  • 在c++中字符串复制与内存复制之间的区别

    1 编程实现strcpy函数 字符串复制的实现 原型char strcpy char strdest const char strSrc 对于上述代码 xff0c 为什么要用char 类型呢 xff1f 为了能够链式表达式 2 内存复制函数
  • static静态变量与普通变量的区别

    1 static全局变量与普通全局变量的区别 全局变量的说明之前再加上static就构成静态全局变量 全局变量本身就是静态存储方式 xff0c 静态全局变量当然也是静态存储方式 这两者在存储方式上没有区别 区别在于 xff0c 非静态全局变
  • VS2013与数据库mysql8.0的连接

    1 准备 xff1a vs2013 mysql 8 0 1 1首先我们到官网上下载mysql 下载完成后解压 xff0c 安装 vs2013下载解压安装 2 我们打开安装后的mysql文件夹 我们一会要重点用到 include 和lib 所
  • 用VS2013中MFC开发视频播放器

    1 搭建开发环境 1 1 vs2013网上有许多软件可以自行下载或者 vs2013的安装包 有需要的留言我给发 1 2 搭建DirectShow开发环境 我参考的书上说要自己下一个DriectShow xff0c 但是我下载了好多次 xff
  • 用VS2013中MFC开发视频播放器(2)

    上一个博客我写了做视频播放器的环境搭建 xff0c 没写完这个项目 xff0c 所以今天在把它详细的写一遍流程 xff0c 介绍一下这个项目的编写 1 需求分析 xff1b 要求开发播放器系统能够播放媒体文件 xff0c 而且还可以进行播放
  • 基于正点原子探索者使用STM32CubeMX+FreeRTOS+LWIP

    开发板是使用正点原子的探索者为例 xff0c PHY芯片可以是LAN8720A和IP101GR xff0c 因为有两份代码参考 xff0c 一份是LAN8720A xff0c 一份是IP101GR 首先第一步 xff1a 我们使用移植好的功
  • C++笔试中遇到的问题

    1 sizeof与strlen的区别 xff1f 答 xff1a sizeof是操作符 xff0c 分配的数组实际所占的内存空间大小 xff0c 不受里面存储内容的影响 strlen是函数 xff0c strlen计算字符串的长度 xff0
  • CRC计算的简单原理及代码实现(python)

    目录 多项式的获取 CRC计算的示例图 示例代码 多项式的获取 举例如下 xff08 其余的多项式依次类推即可 xff09 xff1a 故最终多项式获取的参与异或计算的数据为 xff1a 1011 CRC计算的示例图 假设原始数据为 xff
  • 深度学习训练数据中的特征重要性排名

    查看神经网络模型特征重要性的思路 xff1a 依次变动各个特征 xff0c 通过模型最终预测的结果来衡量特征的重要性 神经网络特征重要性的获取步骤如下 xff1a 训练一个神经网络模型 xff1b 每次对一个特征列进行随机shuffle x

随机推荐

  • (笔记)Python import 其他路径下的文件

    一般情况下 xff0c 如果要import的文件和被import的文件位于同一路径下 xff0c 可以使用 xff1a import 文件名 的方式直接进行引用 但如果这两个文件不在同一路径下 xff0c 就需要在被import的文件路径下
  • (Note)Python osgeo&shapefile库的安装

    1 shapefile anaconda xff1a conda install pyshp pip xff1a pip install pyshpe 2 osgeo 进入Link xff1a https www lfd uci edu g
  • (Note)Python 统计列表中各元素出现的次数

    演示列表 xff1a Demo list 61 1 2 3 3 3 5 6 2 2 0 4 5 2 7 8 4 5 1 3 9 8 7 1 统计列表中不同元素的个数 Demo list 61 1 2 3 3 3 5 6 2 2 0 4 5
  • (Note)海韵&海韵代工的电源-风扇智能启停按钮

    海韵是电源四大厂之一 xff0c 旗下有众多型号的电源 其中 xff0c 部分电源的后部会有一个方形的按钮 xff08 在电源开关左侧 xff09 如图所示 xff1a 这是海韵FOCUS 43 电源特有的 34 HYBRIDMOOE 34
  • (Note)七彩虹30系列显卡——《一键超频》按键

    七彩虹部分30系高端显卡提供了一键超频功能 xff0c 通过按下超频按钮可以实现显卡一键超频 七彩虹显卡的一键超频按钮使用方法 xff1a 按下超频 xff0c 弹起默认 切换需要重启电脑 xff01
  • (Note)优化器Adam的学习率设置

    记录一下知乎看到的问题 xff1a Adam的学习率设置 常用的神经网络优化器Adam的自适应学习率并不是真正意义上的自适应 从统计的角度看 xff0c Adam的自适应原理也是根据统计对梯度进行修正 xff0c 但依然离不开前面设置的学习
  • (Note)深度学习与人工提取的特征

    首先 xff0c 深度学习一般 不需要人工提取特征 如果仅仅给网络提供人工提取的特征 xff0c 反而有可能会造成网络性能的下降 xff08 深度学习模型可能提取到一些人类不易察觉的特征 xff0c 这些特征可能对结果的判定有着较大的贡献
  • Linux驱动开发与裸机开发区别

    Linux驱动开发与裸机开发区别 裸机驱动开发回顾Linux驱动开发思维Linux驱动开发分类 裸机驱动开发回顾 1 底层 跟寄存器打交通 xff0c 有些MCU提供了库 Linux驱动开发思维 1 Linux下驱动开发直接操作寄存器不现实
  • Linux下使用U盘

    第一步 xff1a 插入U盘 xff0c 如果能够识别出U盘 xff0c 则会打印出一些信息 xff1b 第二步 xff1a 查看U盘系统分配给U盘的设备名 xff1b 输入如下命令进行查看 xff1a fdisk l dev sda 如果
  • (Deep Learning)交叉验证(Cross Validation)

    交叉验证 xff08 Cross Validation xff09 交叉验证 xff08 Cross Validation xff09 是一种评估模型泛化性能的统计学方法 xff0c 它比单次划分训练集和测试集的方法更加稳定 全面 交叉验证
  • (Linux)在Ubuntu系统中添加新用户并授予root权限

    向Ubuntu系统中添加新用户并为其授予root权限的步骤如下 打开终端Terminal 输入命令 sudo su 以 root 身份登录 注 sudo su 切换root身份 不携带当前用户环境变量 sudo su 切换root身份 携带
  • (深度学习)类别不平衡数据集中IOU和mIOU的选择

    测试集上的mIOU很高 xff0c 但是实际的分割结果很差 xff0c 几乎没有分割出前景 xff0c 主要是因为要分割的目标占总面积之比太少 xff0c 即出现样本不均衡的问题 此时 xff0c 前景所占的比例太小 xff0c 背景所占的
  • 系统调用,API,运行库函数和C标准库函数的区别

    1 为什么用户程序不能直接访问系统内核模式提供的服务 xff1f 在linux中 xff0c 将程序的运行空间分为内核与用户空间 xff08 内核态和用户态 xff09 xff0c 在逻辑上它们之间是相互隔离的 xff0c 因此用户程序不能
  • 学习四旋翼(二):控制方法之串级PID与卡尔曼滤波(含MATLAB示例)

    暑假期间 xff0c 对于四旋翼有一点兴趣 xff0c 没有亲手做 xff0c 但是看了一些资料 这个系列文章只是对自己看的东西的记录 xff0c 对于想要学习了解相关知识的同学没有任何参考价值 xff01 本篇是系列的第二部分 xff1a
  • Git tag标签与branch分支 区别

    Git中的分支和标签有点类似 xff0c 都是引用或者说指针 关于Git引用可以参阅Git References一章节 一 相似的地方 xff1a 图示如下 xff1a heads和tags文件夹存储的是具体分支和标签 xff1a tags
  • 关于字符串结束符'\0'

    字符串结束符 xff1a 39 0 39 xff0c 其本质就是8位的 0000 0000 xff0c 而字符类型中并没有这个字符 xff08 注意与ASCLL码区别 xff0c 在ASCLL中000 代表NULL xff09 所以用0的转
  • extern “C”的作用详解

    extern 34 C 34 的主要作用就是为了能够正确实现C 43 43 代码调用其他C语言代码 加上extern 34 C 34 后 xff0c 会指示编译器这部分代码按C语言的进行编译 xff0c 而不是C 43 43 的 由于C 4
  • Lab2 p3 围棋吃子的算法实现

    简单介绍下框架 xff1a 1 xff0e 声明一维数组block 作为一个临时变量记录一个块的大小 xff0c 声明一个整型blockLength记录这个块的长度 2 xff0e kill 为吃子的主函数 recersion int i
  • Python爬取皮皮虾视频

    背景 xff1a 今天闲着没事做 xff0c 然后想着刷刷视频 xff0c 然后发现前段时间学习了一下网络爬虫的一些基本应用 xff0c 就想着利用爬虫到网上去爬取一点视频来模拟人为的点击 下载操作 因为皮皮虾是手机端的app xff0c
  • C语言——全局变量的定义与声明

    转自 xff1a https www cnblogs com amanlikethis p 3319744 html C语言中全局变量的定义与声明困扰着许多C语言初学者 本文讲述了全局变量定义与声明的用法 xff0c 而且本为也将阐述这种用