ODR 违规(弱符号被弱符号覆盖)

发布于 2025-01-10 07:39:44 字数 1938 浏览 0 评论 0原文

有以下目录结构:

├── A
│   ├── A.cpp
│   ├── A.hpp
│   ├── A.o
│   └── Evil.hpp
├── B
│   ├── B.cpp
│   ├── B.hpp
│   ├── B.o
│   └── Evil.hpp
├── main.cpp
└── main.o

A.hpp:

#pragma once
#include "Evil.hpp"

struct A {
A();
~A();

Evil mid;
};

A.cpp:

#include "A.hpp"

A::A() {
    printf("OuterClass A ctor\n");
}

A::~A() {
    printf("OuterClass A dtor\n");
}

Evil.hpp: (from A/)

#pragma once
#include <cstdio>

struct Evil {
    Evil() {
        printf("Evil A ctor\n");
    }
};

B.hpp:

#pragma once
#include "Evil.hpp"

struct B {
B();
~B();

Evil mid;
};

B.cpp:

#include "B.hpp"

B::B() {
    printf("OuterClass B ctor\n");
}

B::~B() {
    printf("OuterClass B dtor\n");
}

Evil.hpp:

#pragma once
#include <cstdio>

struct Evil {
Evil() {
    printf("Evil B ctor\n");
}
};

main.cpp

#include "A/A.hpp"

int main(){
A a;
return 0;
}

使用命令编译时:

g++ -c A.cpp
g++ -c B.cpp
g++ -c main.cpp
g++ main.o A.o B.o -o out

输出为:

Evil A ctor
OuterClass A ctor
OuterClass A dtor

但是命令时链接的更改:

g++ main.o B.o A.o -o out

输出是(当 Evil.hpp 定义不同时可能会崩溃):

Evil B ctor
OuterClass A ctor
OuterClass A dtor

我知道链接顺序很重要,但为什么在这种情况下没有定义符号?据我了解,Evil.hpp 在 hpp 文件中完全定义,因此是“内联”的,并且定义存在于所有包含的 cpp 中。有趣的是 nm 在 Ao 和 Bo 中输出的两个符号都是弱符号:

0000000000000000 W _ZN4EvilC1Ev
0000000000000000 W _ZN4EvilC2Ev
0000000000000000 n _ZN4EvilC5Ev

所以我认为这里的问题是:为什么来自 Ao 的弱符号会被来自 Bo 的其他弱符号覆盖?我认为弱符号只能被强符号覆盖? 编译于:

g++(Ubuntu 10.3.0-1ubuntu1)10.3.0

There is following directory structure:

├── A
│   ├── A.cpp
│   ├── A.hpp
│   ├── A.o
│   └── Evil.hpp
├── B
│   ├── B.cpp
│   ├── B.hpp
│   ├── B.o
│   └── Evil.hpp
├── main.cpp
└── main.o

A.hpp:

#pragma once
#include "Evil.hpp"

struct A {
A();
~A();

Evil mid;
};

A.cpp:

#include "A.hpp"

A::A() {
    printf("OuterClass A ctor\n");
}

A::~A() {
    printf("OuterClass A dtor\n");
}

Evil.hpp: (from A/)

#pragma once
#include <cstdio>

struct Evil {
    Evil() {
        printf("Evil A ctor\n");
    }
};

B.hpp:

#pragma once
#include "Evil.hpp"

struct B {
B();
~B();

Evil mid;
};

B.cpp:

#include "B.hpp"

B::B() {
    printf("OuterClass B ctor\n");
}

B::~B() {
    printf("OuterClass B dtor\n");
}

Evil.hpp:

#pragma once
#include <cstdio>

struct Evil {
Evil() {
    printf("Evil B ctor\n");
}
};

main.cpp

#include "A/A.hpp"

int main(){
A a;
return 0;
}

When compiled with commands:

g++ -c A.cpp
g++ -c B.cpp
g++ -c main.cpp
g++ main.o A.o B.o -o out

The output is:

Evil A ctor
OuterClass A ctor
OuterClass A dtor

But when order of linking is changed:

g++ main.o B.o A.o -o out

The output is (and possible crash when Evil.hpp definition is different):

Evil B ctor
OuterClass A ctor
OuterClass A dtor

I know that linking order matters but why in that case symbols are not defined? As I understand Evil.hpp is fully defined in hpp file hence is 'inlined' and definitions are present in all included cpp. The interesting part is that nm outputs in both A.o and B.o both symbols as weak:

0000000000000000 W _ZN4EvilC1Ev
0000000000000000 W _ZN4EvilC2Ev
0000000000000000 n _ZN4EvilC5Ev

So the question here I believe is: why weak symbol from A.o is overriden by other weak symbol from B.o? I thought that weak symbol can be overridden only by strong symbol?
Compiled on:

g++ (Ubuntu 10.3.0-1ubuntu1) 10.3.0

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文