首页 > 编程语言 >C语言多文件编程中全局变量的声明与定义会遇到的问题

C语言多文件编程中全局变量的声明与定义会遇到的问题

时间:2023-08-18 19:57:02浏览次数:39  
标签:全局变量 show int void 编程 C语言 include test main

C语言多文件编程中全局变量的声明与定义会遇到的问题

目录

描述:

  • 在学习C语言的多文件编程的时候,看到声明全局变量竟然和声明函数一样,在.h文件中通过extern关键字声明后,还要在.c文件中"定义一次"有些不解,所以我到百度上看了些博客,那些博客对声明和定义的说法是:
    • extern int a;// 这个是声明。
    • int a;// 这个是定义。
    • int a = 10;// 这样也是定义。
  • 对于网上的声明的定义的说法,我觉得有些问题。
  • 开发工具Clion,编译工具:mingw。

1.创建3个文件,分别是main.c、test.h、test.c,具体代码如下:

1.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
extern int a;

extern void show();

#endif /* _TEST_H */

1.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
int a;

void show(){
    printf("show函数\n");
}

1.1.3 main.c

#include "test.h"


int main(void) {
    a = 10;
    printf("%d",a);

    show();
    return 0;
}

1.1.4 这样能直接编译通过。

2.创建3个文件,分别是main.c、test.h、test.c,具体代码如下:

2.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
extern int a;

extern void show();

#endif /* _TEST_H */

2.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
// int a; 这里注释掉这行代码,看看能不能编译通过。

void show(){
    printf("show函数\n");
}

1.1.3 main.c

#include "test.h"


int main(void) {
    a = 10;
    printf("%d",a);

    show();
    return 0;
}

1.1.4 这样不能直接编译通过。

  • 报了这样一个错:undefined reference to `a'
  • 意思是对“a”的未定义引用。

3.创建3个文件,分别是main.c、test.h、test.c,具体代码如下:

3.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
// extern int a; 注释这行代码,看看能不能编译通过。

extern void show();

#endif /* _TEST_H */

3.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
int a; //这里去掉注释

void show(){
    printf("show函数\n");
}

3.1.3 main.c

#include "test.h"

int main(void) {
    a = 10;
    printf("%d",a);

    show();
    return 0;
}

3.1.4 这样开发工具直接报错,也不能编译通过。

  • 开发工具报错:Use of undeclared identifier 'a'。
  • 意思是:使用未定义的标识符 'a'。
  • 编译报错:error: 'a' undeclared (first use in this function)。
  • 大致意思是:'a' 在main函数第一次使用时,没有定义。

4.创建3个文件,分别是main.c、test.h、test.c,具体代码如下:

4.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
extern int a; // 这次,有无这行代码都不会报错。

extern void show();

#endif /* _TEST_H */

4.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
int a; 

void show(){
    a = 10;
    printf("%d\n",a);
    printf("show函数\n");
}

4.1.3 main.c

#include "test.h"

int main(void) {
    show();
    return 0;
}

4.1.4 这样能直接编译通过。

4.创建4个文件,分别是main.c、test.h、test.c、test2.c 具体代码如下:

4.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
extern int a; // 去掉注释

extern void show();
extern void show2();

#endif /* _TEST_H */

4.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
int a; //这里去掉注释

void show(){
    printf("show函数\n");
}

4.1.3 test.h

#include "test.h"

int a;

void show2(){
    printf("test2.h");
}

4.1.4 main.c

#include "test.h"

int main(void) {
    a = 10;
    printf("%d",a);

    show();
    show2();
    return 0;
}

4.1.5 这样能直接编译通过。

  • 这次,在test.c和test2.c中,都有“ int a; ”这行代码,没有对a进行赋值操作,在main函数中才进制赋值操作。

5.创建4个文件,分别是main.c、test.h、test.c、test2.c 具体代码如下:

5.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
extern int a; // 去掉注释

extern void show();
extern void show2();

#endif /* _TEST_H */

5.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
int a = 10; //这里去掉注释

void show(){
    printf("show函数\n");
}

5.1.3 test.h

#include "test.h"

int a = 20;

void show2(){
    printf("test2.h");
}

5.1.4 main.c

#include "test.h"

int main(void) {
    a = 10;
    printf("%d",a);

    show();
    show2();
    return 0;
}

5.1.5 这次不能直接编译通过。

  • 这次,在test.c和test2.c中,int a 后面加上赋值操作。
  • 这次编译报错: multiple definition of `a'。
  • 意思是:多次定义 ' a '。

6.创建4个文件,分别是main.c、test.h、test.c、test2.c 具体代码如下:

6.1.1 test.h

#ifndef _TEST_H
#define _TEST_H

#include <stdio.h>

// 声明全局变量
// extern int a; // 注释这行代码

extern void show();
extern void show2();

#endif /* _TEST_H */

6.1.2 test.h

#include "test.h"

// 这句代码的具体是声明还是定义?
int a; 

void show(){
    a = 10;
    printf("%d\n",a);
    printf("show函数\n");
}

6.1.3 test.h

#include "test.h"

int a;

void show2(){
    a = 20;
    printf("%d\n",a);
    printf("test2.h");
}

6.1.4 main.c

#include "test.h"

int main(void) {
    show();
    show2();
    return 0;
}

5.1.5 这次能直接编译通过。

  • 这次 a 没有在.h文件中声明。
  • 这次在test.c和test2.c文件中,都对a进行定义且赋值操作。
  • 这次,输出的a的值有时候是10,有时候是20,具体是10还是20和show()与show2()的执行顺序有关。

总结:

  • 1.1 在多文件编程中,如果在.h文件中,通过extern关键字声明了某个全局变量(这里假定为:a),其他.c文件如果想使用这个变量的话,必须定义一次(也就是没有赋值的定义,类似:int a;)
  • 1.2 且无论多少个.c文件导入了该头文件,都可以定义一次该变量,但有个前提,该变量都不能在函数体外赋值。
  • 2.1 在多文件编程中,如果 没有 在.h文件中,通过extern关键字声明了某个全局变量(这里假定为:a),只要 不同时 在定义的时候不赋予初始值,那么都可以定义(类似:int a;)。(赋值方式:在函数中赋值)。
  • 2.2 在不同的.c文件中,定义相同的全局变量(假定为a),他们的地址都相同。
  • 后续会查询资料更新这个博客。

标签:全局变量,show,int,void,编程,C语言,include,test,main
From: https://www.cnblogs.com/wbnyua/p/17641467.html

相关文章

  • 用C语言做一个菱形图案
    如何来完成一个菱形图案的打印呢?首先我们把它简单的看成两个三角组成的图案,分为上下两部分,我们先来完成上半部分,首先肯定是一行一行来打印,为了后期维护方便我们用循环来完成,我们输入几行就打印几行。那一行由什么组成的呢?是用空格和星号来组成的,我们先来第一步打印空格,我们经过发现......
  • 20-面向对象编程-多态
    面向对象编程有三大特征:封装、继承和多态 访问修饰符可以控制属性的访问范围public:表示公共访问级别,可以被任何类访问。protected:表示受保护访问级别,可以被类本身、子类和同一包中的类访问。default(缺省):表示默认访问级别,即如果没有使用访问修饰符,默认是此级别,可以被同一包......
  • 笔记整理--C语言--C语言指针5分钟教程——转载
    C语言指针5分钟教程指针、引用和取值什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量。在这份教程里“引用”表示计算机内存地址。从指针指向的内存读取数据称作指针的取值。指针可以指向某些具体类型的变量地址,例如int、long和double。指针也可......
  • 隧道代理被识别?爬虫编程的应对策略与解决方案
    没有遇到使用了隧道代理后,还是被网站识别到的问题?别急,今天我来分享一些解决识别问题的妙招!这些方法简单易行,让你的爬虫工作顺利进行,快来跟我一起看看吧!先了解一下,为什么爬虫使用隧道代理后仍然被识别?隧道代理是一种通过在本地计算机和目标服务器之间建立一个安全的隧道来隐藏真实IP......
  • java编程题,打印n对括号的全部有效组合
    如题所述,当n=3时,可能的组合有:(()()),((())),()(()),(())(),()()()代码如下(有注释):importjava.util.ArrayList;importjava.util.List;publicclassTest06{/***通过递归生成n对括号的全部有效组合*@paramlist装括号组合的容器*@paramleftRem左括号剩余数量*@paramrightRe......
  • 笔记整理--C语言--Stack的三种含义 - 博客 - 伯乐在线——转载
    【转载】:原文http://www.ruanyifeng.com/blog/2013/11/stack.htmlStack的三种含义-博客-伯乐在线-转载Stack的三种含义学习编程的时候,经常会看到stack这个词,它的中文名字叫做”栈”。理解这个概念,对于理解程序的运行至关重要。容易混淆的是,这个词其实有三种含义,适用于......
  • Java 网络编程
    网络编程1.概述地球村:你在西安,你一个美国的朋友!信件:计算机网络:计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。网络编程的目的:无线电台..........
  • 25大编程代码
    注册功能代码二次优化#如何将校验用户是否已存在和注册用户逻辑合并因为两者其实都属于用户注册功能将校验用户是否存在的代码嵌入到注册代码中即可通过返回值来控制#针对核心逻辑层的函数返回值做了优化返回多个数据目前是两个第一个用于告知......
  • C语言的指针图示
    所谓指针定义,可以认为一个指针位置有2个结构,第一个结构就是指针所指向的地址,第二个结构就是地址里的数据。对赋值操作来说,指针变量在左边和右边不一样,在左边是取地址(也可以理解为容器),在右边的是取地址处的值(也就是容器里的东西)。//结合图示,这里的*ppp你觉得是修改哪个变量的......
  • 笔记整理--C语言--失落的C语言结构体封装艺术 - 博客 - 伯乐在线——转载
    失落的C语言结构体封装艺术-博客-伯乐在线转载1.谁该阅读这篇文章本文是关于削减C语言程序内存占用空间的一项技术——为了减小内存大小而手工重新封装C结构体声明。你需要基本的C语言的基本知识来读懂本文。如果你要为内存有限制的嵌入式系统、或者操作系统内核写代码,那......