2

这是主题代码:

外部文件.cpp

int i = 10;

主文件.cpp

#include <iostream>

using namespace std;

extern int i;
int main(int param)
{
    cout << i << '\n';
    int i = 0;
    cout << i << '\n';
    cout << ::i << '\n';
}

编译此程序时(使用 Visual Studio 2008),它工作正常,输出将是:

10
0
10

这对我来说并不奇怪,这是范围的问题。

但是让我感到困惑的是:文件如何从另一个文件中mainfile.cpp获取值(在我们的例子中)?仅仅是因为它们位于同一个目录中吗?或相同的解决方案?i.cppexternfile.cpp

并且以更好的方式:在编译项目时如何“合并”源文件(如果我应该指定,使用 VS2008)?它们按什么“顺序”排列?它们的范围如何?

4

3 回答 3

3

“正常”VC++ 项目1指示 VC++ 将每个源文件自己编译为“目标文件”(或目标模块),其中编译器为尚未解析的符号(如external变量或函数)留下“占位符”声明但未定义)。

然后,链接器将所有目标文件绑定在一起,链接器将它们绑定在一起以生成最终的可执行文件。在此段落中,“占位符”被替换为它们所指的代码/数据的实际地址,这些地址在各种目标文件中定义。如果未找到某些需要的定义,则会出现未定义的引用错误,如果多次找到某个符号,则会出现多重定义错误2

有关经典链接模型的更多信息,请查看 Raymond Chen 的这篇文章(如果您有兴趣,请查看整个系列)。


  1. 当然还有更多灵活性的空间,这里我只是描述VC++中的常见情况。
  2. 这是 C++“一个定义规则”的结果;尽管如此,还是有一些例外,特别是inline函数和template实例化;在这些情况下,链接器只取它喜欢的任何东西(这应该不是问题,因为此类对象的多个定义必须相同)。
于 2013-01-20T00:58:46.590 回答
3

您的 IDE VS2008 将您的源文件传递给编译器。编译器将您的源文件构建为目标文件,然后将这些文件传递给链接器,链接器链接这些文件以及您的包含文件。

然后链接器将输出所有这些文件的二进制表示,无论是 dll、lib 还是 exe。

这是对所发生事情的一个非常基本的总结,还有更多的过程在进行。

于 2013-01-20T00:59:40.067 回答
2

如果您手动执行此操作,则运行 C 或 C++ 程序需要 4 个步骤

1 - 预处理,主要处理 C 宏、#define 等。

2 - 编译,文件被转换为带有外部符号表的目标代码,以便以后可以解决这些问题

3 - 链接,解决外部引用,如果找不到则报告任何错误

4 - 运行代码。

所有这些都由 IDE VS2008 自动完成。它使这些步骤根据需要进行,如果文件没有更改,则不会重新编译,如果不需要链接,则不会完成。在 .Net 中,制作程序集等需要更多步骤。

于 2013-01-20T01:04:37.913 回答