同一班级,不同大小...?

发布于 2024-09-30 11:31:10 字数 1557 浏览 2 评论 0原文

看看代码,你就会明白我的困惑了。

Test.h

class Test {
public:
#ifndef HIDE_VARIABLE
    int m_Test[10];
#endif
};

Aho.h

class Test;

int GetSizeA();
Test* GetNewTestA();

Aho.cpp

//#define HIDE_VARIABLE
#include "Test.h"
#include "Aho.h"

int GetSizeA() { return sizeof(Test); }
Test* GetNewTestA() { return new Test(); }

Bho.h

class Test;

int GetSizeB();
Test* GetNewTestB();

Bho.cpp

#define HIDE_VARIABLE   // important!
#include "Test.h"
#include "Bho.h"

int GetSizeB() { return sizeof(Test); }
Test* GetNewTestB() { return new Test(); }

TestPrj.cpp

#include "Aho.h"
#include "Bho.h"
#include "Test.h"

int _tmain(int argc, _TCHAR* argv[]) {
    int a = GetSizeA();
    int b = GetSizeB();

    Test* pA = GetNewTestA();
    Test* pB = GetNewTestB();

    pA->m_Test[0] = 1;
    pB->m_Test[0] = 1;

    // output : 40     1
    std::cout << a << '\t' << b << std::endl;

    char temp;
    std::cin >> temp;

    return 0;
}

Aho.cpp 没有 #define HIDE_VARIABLE,因此 GetSizeA() 返回 40,但是 Bho.cpp 执行 #define HIDE_VARIABLE,因此 GetSizeB() 返回 1。 但是,Test* pATest* pB都有成员变量m_Test[]。

如果 Bho.cpp 中的类 Test 的大小是 1,那么 pB 就很奇怪,不是吗?

我不明白发生了什么事,请告诉我。 提前致谢。

环境: Microsoft Visual Studio 2005 SP1(或 SP2?)

See the code, then you would understand what I'm confused.

Test.h

class Test {
public:
#ifndef HIDE_VARIABLE
    int m_Test[10];
#endif
};

Aho.h

class Test;

int GetSizeA();
Test* GetNewTestA();

Aho.cpp

//#define HIDE_VARIABLE
#include "Test.h"
#include "Aho.h"

int GetSizeA() { return sizeof(Test); }
Test* GetNewTestA() { return new Test(); }

Bho.h

class Test;

int GetSizeB();
Test* GetNewTestB();

Bho.cpp

#define HIDE_VARIABLE   // important!
#include "Test.h"
#include "Bho.h"

int GetSizeB() { return sizeof(Test); }
Test* GetNewTestB() { return new Test(); }

TestPrj.cpp

#include "Aho.h"
#include "Bho.h"
#include "Test.h"

int _tmain(int argc, _TCHAR* argv[]) {
    int a = GetSizeA();
    int b = GetSizeB();

    Test* pA = GetNewTestA();
    Test* pB = GetNewTestB();

    pA->m_Test[0] = 1;
    pB->m_Test[0] = 1;

    // output : 40     1
    std::cout << a << '\t' << b << std::endl;

    char temp;
    std::cin >> temp;

    return 0;
}

Aho.cpp does not #define HIDE_VARIABLE, so GetSizeA() returns 40, but
Bho.cpp does #define HIDE_VARIABLE, so GetSizeB() returns 1.
But, Test* pA and Test* pB both have member variable m_Test[].

If the size of class Test from Bho.cpp is 1, then pB is weird, isn't it?

I don't understand what's going on, please let me know.
Thanks, in advance.

Environment:
Microsoft Visual Studio 2005 SP1 (or SP2?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

简单 2024-10-07 11:31:10

您违反了单一定义规则 (ODR) 的要求。您的程序的行为是未定义的。这是这里唯一发生的事情。

根据 ODR,具有外部链接的类必须在所有翻译单元中以相同的方式定义。

You violated the requirements of One Definition Rule (ODR). The behavior of your program is undefined. That's the only thing that's going on here.

According to ODR, classes with external linkage have to be defined identically in all translation units.

娇纵 2024-10-07 11:31:10

您的代码表现出未定义的行为。您违反了一个定义规则(类Test的定义不同两个地方)。因此,编译器可以做任何它想做的事,包括“奇怪的”行为。

Your code exhibits undefined behavior. You are violating the one definition rule (class Test is defined differently in two places). Therefore the compiler is allowed to do whatever it wants, including "weird" behavior.

心房敞 2024-10-07 11:31:10

除了ODR。

大多数问题是由于仅在 cpp 文件中包含标头而导致的,这允许您更改编译单元之间的定义。

但是,Test* pA 和 Test* pB 都有成员变量 m_Test[]。

不,pB 没有 m_Test[] 但 TestPrj 编译单元不知道这一点,并且正在应用错误的类结构,因此它将进行编译。
除非您在调试中编译并捕获内存溢出,否则大多数情况下不会发现问题。
pB->m_Test[9] = 1; 将导致写入未由 pB 分配的内存,但可能是也可能不是可供您写入的有效空间。

In addition to ODR.

Most of the grief is caused by including the headers only in the cpp files, allowing you to change the definition between the compilation units.

But, Test* pA and Test* pB both have member variable m_Test[].

No, pB doesn't have m_Test[] however the TestPrj compilation unit doesn't know that and is applying the wrong structure of the class so it will compile.
Unless you compile in debug with capturing of memory overrun you would most times not see a problem.
pB->m_Test[9] = 1; would cause writing to memory not assigned by pB but may or may not be a valid space for you to write.

最美的太阳 2024-10-07 11:31:10

就像这里许多人所说的那样,您违反了所谓的单一定义规则 (ODR)。

了解 C/C++ 程序的汇编方式非常重要。也就是说,翻译单元(cpp 文件)是单独编译的,彼此之间没有任何联系。接下来链接器根据编译器生成的符号和代码段来汇编可执行文件。它没有任何高级类型信息,因此它无法(也不应该)检测问题。

这样你实际上就欺骗了编译器,打败了自己,踢了自己的脚,无论你喜欢什么。

我想提一下的一点是,由于各种包含头文件和杂项定义的细微变化,实际上 ODR 规则经常被违反,但通常没有问题,人们甚至没有意识到这一点。

例如,一个结构可能有一个 LPCTSTR 类型的成员,它是指向 char 或 wchar_t 的指针,具体取决于定义、包含和等等。但这种类型的违规行为“几乎可以”。只要您实际上不在不同编译的翻译单元中使用此成员,就没有问题。

还有许多其他常见的例子。有些是由类内实现的成员函数(内联)产生的,这些函数实际上在不同的翻译单元中编译成不同的代码(例如,由于不同翻译单元的不同编译器选项)。

不过,这通常是可以的。然而,在您的情况下,结构的内存布局已经改变。这里我们有一个真正的问题。

Like many people told here, you've violated the so-called One Definition Rule (ODR).

It's important to realize how C/C++ programs are assembled. That is, the translation units (cpp files) are compiled separately, without any connection to each other. Next linker assembles the executable according to the symbols and the code pieces generated by the compiler. It doesn't have any high-level type information, hence it's unable (and should not) to detect the problem.

So that you've actually cheated the compiler, beaten yourself, shoot your foot, whatever you like.

One point that I'd like to mention is that actually ODR rule is violated very frequently due to subtle changes in the various include header files and miscellaneous defines, but usually there's no problem and people don't even realize this.

For instance a structure may have a member of LPCTSTR type, which is a pointer to either char or wchar_t, depending on the defines, includes and etc. But this type of violation is "almost ok". As long as you don't actually use this member in differently compiled translation units there's no problem.

There're also many other common examples. Some arise from the in-class implemented member functions (inlined), which actually compile into different code within different translation units (due to different compiler options for different translation units for instance).

However this is usually ok. In your case however the memory layout of the structure has changed. And here we have a real problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文