.net - 如何实现一个定义规则

标签 .net c++ one-definition-rule

This post引用一个定义规则。

Wikipedia is pretty bad on explaining how to implement it

我在哪里可以找到有关在 C++ .NET 中遵循的准则的良好资源?

最佳答案

一个定义规则基本上意味着一个变量/函数只能位于已编译可执行文件地址空间中的一个位置。一种思考方式是在编译时,有一个内存数组用于编译后的程序(目标代码),以及一个查找表来引用变量/函数位置。这是在每个进程级别上完成的。假设下面是一个简单的程序:

文件1.cpp

int square(int x); // this is a declaration
extern int someVariable; // this is a declration

void square(int x)  // this is a definition
{
    return x * someVariable;
}

文件2.cpp

int square(int x); // this is a declaration

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}       

当编译器开始编译目标代码时,它会读入声明,并将内容放入其表中。在编译 file1.cpp 的最后,它会得到这样的结果:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    12 34 56 78 aa XX XX XX XX ab cd
definition:
    square: starts at address 0

这假设函数被编译为那些特定的汇编指令。在链接器时,XX XX XX XX 将被 someVariable 的地址替换。

File2 最终是这样的:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    00 00 00 00 12 34 56 78 12 34 56 YY YY YY YY 23 21
definitions:
    someVariable: starts at address 0
    main: starts at address 4

在这种情况下,YY 将替换为 square 的地址。

这就是链接器发挥作用的地方。链接器的工作是遍历列表,并在编译时建立一个表,列出所有内容在程序地址空间中的位置。但是,如果两个目标文件在尝试链接时具有相同的变量定义,则会出现问题。如果在上面的例子中有两个 someVariable 的定义,那么它就不知道用什么来代替 YY 了。同样,如果没有 定义,则会出现难看的链接器错误。

该规则的“解决方案”是对您的文件进行分区,以便您仅在 .cpp 文件中具有定义,并在 .h 文件中具有事物的声明,因此上面的示例将变为:

文件1.cpp

#include "file2.h"

void square(int x)  // this is a definition
{
    return x * someVariable;
}

文件1.h

int square(int x); // this is a declaration

文件2.cpp

#include "file1.h"

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}

文件2.h

extern int someVariable;

请注意,这是一个非常简单的示例,它并不真正适用于 .NET,因为在声明和定义之间没有区别的概念。

关于.net - 如何实现一个定义规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/379916/

相关文章:

c# - 如何将自定义窗口窗体置于安装项目窗口顶部?

.net - 为什么克隆(在 .NET 中)如此困难?

c++ - 静脉端到端延迟

c++ - 如何检查是否设置了 std::string?

c++ - 类方法的显式特化 - 符号已定义

.net - 给定一个 .winmd 文件,我们在哪里可以找到真正的实现 DLL?

c# - RX,重试并允许处理异常

c++ - (ODR 使用问题)不同文件中同名结构的 priority_queue

c++ - 通用模板化枚举空值

c++ - emplace_back 导致静态 constexpr 成员上的链接错误