多文件程序中的范围

Posted

技术标签:

【中文标题】多文件程序中的范围【英文标题】:scope in multi-file program 【发布时间】:2012-10-18 11:11:17 【问题描述】:

我有一个程序,除了 main.cpp 和一个常量头之外,还有两个外部文件。所以总共四个文件。它们包含以下代码:

main.cpp

#include <iostream>
using namespace std;

int ext1_func();
int ext2_func();

int main()

    int i;
    i = ext1_func();
    cout <<  i << endl;

    i = ext2_func();
    cout << i << endl;

    return 0;

ext1.cpp

#include "const.h"
int asd1=1;

int ext1_func()

   return temp_int;


ext2.cpp

#include "const.h"
int asd2 = 2;

int ext2_func()

   return temp_int;

const.h

#ifndef CONST_H
#define CONST_H

const int temp_int=1;

#endif

我想要的是:

1) ext1.cpp 中声明的任何变量都应该为 ext1.cpp 中的函数所知,对于 ext2.cpp 也是如此。所以“asd1”必须只有“ext1_func”知道,“asd2”才知道“ext2_func”。

2) “exp1.cpp”和“ext2.cpp”中的函数必须能够看到“const.h”中定义的所有值

我相信我编写和附加的代码满足这些要求,但我想问一下我这样做是否正确?有没有比我建议的更简单的方法来获得所需的行为?

提前致谢。

奈尔斯。

【问题讨论】:

所显示代码的最大问题是(1)asdN 变量在其源文件之外可见(在各种答案中扩展讨论),以及(2 ) 没有一个标头声明用于强制使用函数的代码 (main.cpp) 和定义函数的代码 (extN.cpp) 之间的一致性。当然,C++ 具有类型安全的链接(与我主要工作的 C 不同)。但是,一般来说,最好不要在源文件中编写 extern 声明——应该有一个头文件来声明用于强制一致性的函数。 【参考方案1】:

在编译单元级别,您在“全局”范围内声明的符号都链接到全局变量空间。

避免这种情况的旧方法是将它们声明为静态。新方法是将它们放入匿名命名空间中。它们也可以在那里声明为静态的。

ext1.cpp

namespace 
  /*static*/ int asd1=1;  

header 中的 const 是可以的,这样声明的常量有特殊的地位,实际上编译器可以在代码中代入值。不过,理想情况下,您至少应该将它们包装在一个(命名的)命名空间中,以避免污染全局命名空间。修改值(使用 const_cast)将是未定义的行为。

如果它是非常量并且您真的想要一个全局的(通常不是一个好主意),您需要在标头中使用 extern 关键字,然后在单个编译单元中创建它的实例。

【讨论】:

关于“标题中的 const 没问题,[...]”,谢谢。我担心以这种方式定义全局常量是一种糟糕的编程风格,现在我将保持原样。 全局常量是可以的,但理想情况下你应该把它们放到一个(命名的)命名空间中,以免“污染”全局命名空间。【参考方案2】:

我不会在 main.cpp 中重复 ext1_func()ext2_func() 原型,而是为每个函数定义一个头文件,并在其中添加函数原型:

// ext1.h
#ifndef EXT1_H_INCLUDED
#define EXT1_H_INCLUDED

int ext1_func();

#endif // EXT1_H_INCLUDED


// ext2.h
#ifndef EXT2_H_INCLUDED
#define EXT2_H_INCLUDED

int ext2_func();

#endif // EXT2_H_INCLUDED

在 main.cpp 中:

#include "ext1.h"
#include "ext2.h"

在 ext1.cpp 和 ext2.cpp 中,仅对源文件本地的变量使用匿名命名空间

// ext1.cpp
#include "const.h"
#include "ext1.h"

namespace 

int asd1=1;

 // anonymous namespace


int ext1_func()

   return temp_int;   

与 ext_2.cpp 类似。

您可能还想在头文件中使用方便的 #pragma once,而不是 #ifndef/#define 包含守卫。

【讨论】:

在“const.cpp”中添加定义而不是在“const.h”中添加定义有什么好处? @niles_1710373:有关是否在标头中定义常量的讨论,请参阅 AndreyT 的 answer。【参考方案3】:

您应该将ext1.cppext2.cpp 中的变量定义为静态,以防止它们被其他文件看到。但是,这是一种非常糟糕的构建方式。相反,您应该将代码分成不同的类。有关详细信息,请参阅this。

【讨论】:

我一般不同意您的观点,即“您应该将代码分成不同的类”。也许应该有类和对象,但 C++ 通常不支持“一切都必须在一个类中”范式。 -1 指向高度抽象的关于 OOP 的 Wikipedia 页面“了解详情”。此外,C++ 无缘无故不支持匿名命名空间之类的东西,而且当前的程序太琐碎,无法保证 OO 设计。【参考方案4】:

当您想将变量设置为翻译单元(.cpp 文件)的本地变量时,您可以将它们放入匿名命名空间,如下所示:

namespace

    int local_variable = 1;

您也可以使用旧的 C 方式来替代:

static int local_variable = 1;

您也不应该在头文件中定义变量,因为它会在包含此头文件的每个.cpp 模块中重复。您应该在const.h 中将其声明为外部:

extern int external_variable;

然后在对应的const.cpp文件中定义如下:

int external_variable = 1;

【讨论】:

谢谢!但是可以在“const.h”中定义一个常量变量吗?它还会在每个模块中重复吗? @niles_1710373,对于const int 和其他整数类型都可以。

以上是关于多文件程序中的范围的主要内容,如果未能解决你的问题,请参考以下文章

Java中的命名管道和多线程

索引超出了 MSCORLIB.DLL 中的数组范围

Selenium 中的多线程/多处理

5 多进程copy文件

cpp程序使用fstream进行多文件输入

C ++中的多线程文件散列[关闭]