首页 > 编程语言 >Chapter.1 Extern | 我的变量怎么重复了? ——C++查漏补缺

Chapter.1 Extern | 我的变量怎么重复了? ——C++查漏补缺

时间:2022-12-25 14:24:11浏览次数:66  
标签:test1 文件 查漏 int Chapter.1 C++ extern cpp ------

近期在学习C++,配合大牛书Primer看的效果还是很不错的。学到指针时又遇到了extern的使用,但自己回忆起来,好像在之前学过的内容里并没有对extern有非常深刻的印象。

 

于是结合着书中的内容和自己查阅的博客,我写出了以下代码进行测试。

IDE版本:Visual Studio 2022 Community

// ------test1.cpp------
#include <iostream>
using namespace std;

extern int i;
extern int print1();

int main()
{
    print1();
    return 0;
}
// ------test2.cpp------
#include <iostream>
using namespace std;

int i;

int print1() {
    i = 1;
    cout << i << endl;
    return 0;
}

注:test1.cpp与test2.cpp处于同一解决方案的同一文件夹下(文件夹名:源文件)

 

 

 

此时运行test1.cpp,可以看到正常的输出结果:

 

 

 

 浏览了博客《C++中extern关键字使用》后得知,通过引入头文件、在头文件中定义的方式,可以达到与extern一样的引用其他文件中变量的效果,于是尝试:

// ------test1.cpp------
#include <iostream>
#include "test11.h"
using namespace std;

//extern int i;
//extern int print1();

int main()
{
    print2();
    return 0;
}
// ------test11.h------
#pragma once
#include <iostream>
using namespace std;
int i1 = 1002;

int print2() {
    cout << ++i1 << endl;
    return 0;
}

注:test1.cpp目录无变化,test11.h文件在同一解决方案内的“头文件”目录里

 

 

 

此时运行test1.cpp,同样能看到正常的输出结果

 

 

 

到此,定义在其它文件中的函数和变量,可以使用的两种方法已经试验完成了:

        一、使用头文件调用,这时候,函数和变量必须在头文件中定义和声明。

        二、使用extern关键字调用,这时候函数和变量在.cpp或者.c文件中定义和声明。

 

但此时大聪明的我,又把这两种方式揉到了一起(其实是没区分开),于是有了如下的代码:

// ------test1.cpp------
#include <iostream>
#include "test2.cpp" using namespace std; //extern int i; //extern int print1(); int main() { print1(); return 0; }
// ------test2.cpp------
// 该文件内容无变化,此处仅为方便阅览
#include <iostream>
using namespace std;

int i;

int print1() {
    i = 1;
    cout << i << endl;
    return 0;
}

我在test1.cpp中引入了test2.cpp,随后在main函数中直接调用了 print1 函数。此时链接器报错:

 

 test1中已经定义了 i 变量和 print1 函数,出现了多重定义。正在我好奇为什么将头文件引用换成源文件引用就会引发重复定义时,我在上述博客中看到了如下的一句话:

如果一个工程现编译cpp文件,在把多个目标文件链接成为可执行文件,而两个或多个文件中,定义了相同的全局变量,那么,程序编译的时候不会报错,因为编译器单独编译每个文件,在链接可执行文件的时候,由于多个目标文件中含有相同的全局变量,而生成可执行文件的时候,任何文件中定义的全局变量对其它目标文件都是可见的,此时由于变量定义冲突而发生错误。

 

原博客中给出的代码为在两个.cpp文件中均定义 i 变量和 print 函数,与我代码的写法不同,但报错内容是相同的。

而博客中紧接着的一段话给了我答案:

PS:定义在.h文件中的函数和变量不能使用extern变量声明,原因是#include <filename>在预编译的时候将.h文件中的内容插入了cpp文件中,因此编译器找得到在其它.h文件中定义的变量或者函数。编译的时候,只编译cpp文件的内容,.h文件时不参与编译,如果使用extern声明在.h文件中定义的变量或者函数,那么声明为extern的变量和函数在其它.cpp文件中找不到,因此程序编译的时候就发生了错误。

 

在预编译时,#include "test2.cpp" 指令已经将test2.cpp文件中的内容插入到了test1.cpp文件中,因此在test1编译时已经对 i 变量和 print1 函数进行了定义;随后编译器再编译test2.cpp,自然会引发全局变量定义冲突的错误(因为test2里的内容已经作为test1的一部分编译过了,此时是内容的第二次编译)。

 

除了我上面列出的错误写法之外,上面的话也列出了另一种非法的extern使用:

// ------test1.cpp------
#include <iostream>
using namespace std;

extern int i;
extern int print2();

int main()
{
    print2();
    return 0;
}
// ------test11.h------
//文件内容无变化,此处仅为方便阅览
#pragma once
#include <iostream>
using namespace std;
int i1 = 1002;

int print2() {
    cout << ++i1 << endl;
    return 0;
}

此时编译器报错:

 

 

虽然test1.cpp中对 i 变量和 print2 函数声明了extern,但由于没有任何.cpp文件中对该两项内容进行定义,因此链接器无法找到这两项的实际定义的位置。

 

总结:C++中,关于引用其他文件中变量和函数的方法共有两种:

1. 在文件中插入.h头文件,使用头文件中定义的变量和函数;

2. 使用extern声明在其他.cpp文件中定义好的变量和函数(此时变量和函数通常为全局的)

 

本文也列出了两种错误的使用方法,请注意不要将其与正确用法混淆。

标签:test1,文件,查漏,int,Chapter.1,C++,extern,cpp,------
From: https://www.cnblogs.com/sqyl/p/17003960.html

相关文章

  • C++模板
    //-std=c++14//-O2//#pragmaGCCoptimize("Ofast")//next_permutation(a+1,a+1+n)#include<bits/stdc++.h>#definebintBigInteger#definehhputs("");#definey......
  • 基于qml创建最简单的图像处理程序(2)-使用c++&qml进行图像处理
     《基于qml创建最简单的图像处理程序》系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面课程1附件基于qml创建最简单的图像处理程序(2)-......
  • C++ empty函数
    https://blog.csdn.net/qq_41598072/article/details/99973908empty是用来测试变量是否已经配置。若变量已存在、非空字符串或者非零,则返回false值;反之返回true值。所......
  • C++ sort函数中利用lambda进行自定义排序规则
    在c++中,由于sort()函数默认提供的是由小到大的排序方式,因此有时候我们需要自定义排序规则来实现由大到小的排序。一维vector<>排序#include<bits/stdc++.h>usingnam......
  • C++:重载运算符
    基本概念通常我们自定义的类类型,不具有内置类型的一些操作,比如int类型的算术运算,指针类型的解引用、取地址操作,容器类型的下标操作等。因此,如果希望我们自定义的类类型......
  • C++科研人员信息管理系统
    C++科研人员信息管理系统某科研团队主要有四类人员:科研主管、研究员、研究助理和实习研究员。现在,需要存储这些人员的姓名、编号、级别、当月薪水,计算月薪总额并显示全部......
  • C/C++在线餐馆预订管理系统
    C/C++在线餐馆预订管理系统软件学院实训任务书一、实训名称实践环节数据结构与算法实训项目名称在线餐馆预订管理系统二、学生信息班级......
  • c++ 模板参数有默认值时模板特例化匹配问题
    如下的源码:template<typenameT,typenameU=int>classS{//#1public:voidf1(){};};template<>classS<void>{ //#2public:voidf2(){};};......
  • 蓝桥-13届-C++-B组-省赛-F题-统计子矩阵
    直达链接主要解题思路分为两个部分,1是构造二维前缀和计算矩阵和,降低每次求和的时间复杂度;2是对所有子矩阵的遍历求和过程,因为需要两个坐标,遍历4个行/列值,4层for循环时间复......
  • C++基础3
    C++基础3typedef为现有类型创建一个新名字主要有以下几种形式:为基本数据类型定义别名为指针定义别名为自定义数据类型定义别名为数组定义别名声明函数定义新......