【问题标题】:How to implement One Definition Rule如何实现一个定义规则
【发布时间】:2008-12-19 01:56:23
【问题描述】:

This post 引用单一定义规则。

Wikipedia is pretty bad on explaining how to implement it

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

【问题讨论】:

  • “实施”是什么意思?如何避免违规?

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


【解决方案1】:

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

file1.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;
}

file2.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。同样,如果有 no 定义,那么你会得到丑陋的链接器错误。

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

file1.cpp

#include "file2.h"

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

file1.h

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

file2.cpp

#include "file1.h"

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

file2.h

extern int someVariable;

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

【讨论】:

  • 这是我很长时间以来看到的一个非常简单的概念的最复杂的描述。
【解决方案2】:

遵守单一定义规则的最简单方法是将定义放在 .cpp 文件中而不是头文件中。

人们有时会使用宏和/或预处理器条件将定义放入头文件中,以使对象或函数仅在一个编译单元中定义。但通常将定义放在 .cpp 文件中会更容易(当然也更容易理解)。

【讨论】:

    猜你喜欢
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 2022-12-03
    • 2020-09-30
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多