1

假设我编译了一个包含这段代码的源文件,

struct Point
{
    int x;
    int y;
};

struct Size
{
    int x;
    int y;
};

由于PointSize完全相同(就其成员的内存布局而言),编译器是否会struct在目标文件中生成重复代码(每个代码一个)?这是我的第一个问题。


现在,让我们struct Size从源代码中删除 ,并使用它来定义它typedef,就像这样,

typedef Point Size;

现在编译会做什么?它会重复代码吗(因为 typedef 不仅仅是重命名,而不仅仅是重命名)?


现在假设我们有一个这样的类模板:

template <int UnUsed>
class ConcreteError : public BaseError {
public:
    ConcreteError () :BaseError(), error_msg() {}

    ConcreteError (int errorCode, int osErrorCode, const std::string& errorMessage)
        :BaseError(errorCode, osErrorCode, errorMessage){}
};

然后我们设置一些定义,像这样,

typedef ConcreteError<0> FileError;
typedef ConcreteError<1> NetworkError;
typedef ConcreteError<2> DatabaseError;

由于int UnUsed类的实现中没有使用模板参数(只是假设),所以看起来这种情况与具有完全相同的内存布局的多个类完全相同(类似于struct Pointand的情况struct Size),是否会出现重复代码目标文件?

如果我们这样做会怎样,

typedef ConcreteError<0> FileError;
typedef ConcreteError<0> NetworkError;
typedef ConcreteError<0> DatabaseError;

这种情况是否更好,因为现在我们在 typedefs 中使用相同的实例化类?

PS:这个类模板代码取自这里:

如何使用 C++ 中的模板编程从基类创建派生类?


实际上,我不知道编译器如何从源代码生成目标文件,以及它如何处理类名、成员、其他符号等等。它如何处理 typedef?这有什么用,

typedef int ArrayInt[100];

ArrayInt这里有类型吗?什么代码编译器在目标文件中为它创建?存储在哪里100

4

3 回答 3

2

首先,没有为您包含的第一个结构定义生成代码,因此比较这两种类型毫无意义。但在 C++ 中,类型名称很重要,因此 astruct A肯定与 a 区别对待struct B

typedef创建类型别名,因此 typedef-ed 类型确实是原始类型(它不会创建不同的类型)。

ConcreteError<0>是与 不同的类型ConcreteError<1>

当参数在数据布局方面相同并且函数不需要调用不同实际的数据上的其他子函数时,我认为没有任何东西可以阻止编译器变得时髦并将损坏的函数名称别名为相同的代码类型 和 函数 对 这 两种 类型 做 等效 的 事情, 但 我 不 认为 这 在 实践 中 是 真正 做到 的. 实际上有编译器可以做事(见下面 Ben 的评论)。

对于最后一个 typedef (都是 的别名ConcreteError<0>),只创建了一个“版本” ConcreteError(因为只有那个被实例化了)。

于 2010-12-17T17:44:09.600 回答
2

您的示例中的任何一行都不会在目标文件中生成任何代码。或者,更准确地说,它根本不会生成任何数据。我认为“代码”只是指处理器指令。

目标文件中的数据分为三段:代码、静态数据和常量数据。

代码是由实际的函数定义(带有函数体,而不仅仅是声明)生成的,内联函数除外。内联函数每次实际使用时都会生成代码。模板函数在实例化时会生成代码,但多个实例化通常由编译器、链接器或两者优化为单个实例。

静态数据是通过定义全局变量、静态成员变量(同样,实际定义而不仅仅是类内的声明)和静态局部变量来生成的。不得使用const修饰符声明变量以转到静态数据段。

常量数据由与静态数据相同类型的变量声明生成,但带有const修饰符、浮点文字和字符串文字,可能还有更多文字,具体取决于硬件平台。操作系统实际上可能不允许对硬件级别的常量数据进行写访问,因此如果您尝试在那里写一些东西,您的程序可能会因访问冲突或分段错误而崩溃。

我不是这种低级事物的专家,所以我可能遗漏了一些东西,但我认为我很好地描述了整体情况。

除非我真的错过了什么,否则程序中的任何其他内容都不会在目标文件中生成任何数据,尤其是声明和类型定义。这些由编译器在内部使用。因此,当编译器看到一个结构定义时,它会记住它由两个 32 位整数组成。当它找到一些使用该结构的真实代码时,它知道它必须生成与两个 32 位整数一起工作的代码,必须分配至少 8 个字节来存储它等等。但是所有这些信息都在编译时在内部使用,并没有真正进入目标文件。如果 C++ 有类似反射的东西,那就另当别论了。

请注意,虽然定义大量结构不会向您的目标文件添加任何内容,但它可能会增加编译器本身的内存使用量。所以你可能会说定义相同的东西会导致编译时的数据重复,而不是运行时的重复。

于 2010-12-17T19:39:01.277 回答
0

不,没有未使用的 PODS 的重复代码。如果你使用它们,将会有两个整数,并且可能在内存中分配给它们一些填充。当然,它们看起来都一样,所以你想称之为什么是有争议的,但它并不比在两个地方使用相同的类型更“重复”。

不,没有带有别名的重复代码。实际上根本没有代码。

也许,取决于编译器是否使用某些优化。

也许。取决于您的 typedef 是否在不同的翻译单元中使用以及您的编译器在删除重复实例方面的能力如何。

不,它是 int[100] 的别名。

在很大程度上,“这个结构产生多少机器代码”这个问题完全取决于实现。

于 2010-12-17T17:50:29.480 回答