CPP 同名结构体的同名方法调用问题,违反单一定义规则(ODR)

环境:
ubuntu 20.04
g++ gcc version 9.4.0

1.问题

这里有个更简练的说明,觉得挺好的,附上:
遵循 One Definition Rule - C/C++ 安全规则

开发时遇到一个奇怪的问题,调用某个结构体变量的函数,没有得到预期的结果。但是,每个数据成员的值又是对的。

增加日志打印后,最终发现调用的是另一个同名结构体的同名函数。也就是发生了 ODR (One Definition Rule) 违规问题。

在这里用最小代码,复现下这个问题。

a.h:

#pragma once

#include <iostream>

struct A
{
    int x;
    int y;
    //构造函数

    A()
    {
        std::cout << __FILE__ << ":" << __FUNCTION__ << std::endl;
    }
    void function()
    {
        std::cout << __FILE__ << ":" << __FUNCTION__ << std::endl;
        std::cout << "x" << ":" << x << std::endl;
        std::cout << "y" << ":" << y << std::endl;
    }
};

b.h

#pragma once
#include <iostream>

struct A
{
    int y;
    A()
    { 
        std::cout << __FILE__ << ":" << __FUNCTION__ << std::endl;
    }
    void function()
    {
        std::cout << __FILE__ << ":" << __FUNCTION__ << std::endl;
        std::cout << "y" << ":" << y << std::endl;
    }
};

c.h

#pragma once

class C{
public:
    void dosomething();
};

c.cpp

#include "c.h"
#include "b.h"

void C::dosomething()
{
    A a;
    a.y = 3;
    a.function();
}

main.cpp

#include "a.h"
#include "c.h"

int main()
{
    A a;
    a.x = 1;
    a.y = 2;
    a.function();

    C c;
    c.dosomething();
  
    return 0;
}

目前的发现是,对于g++编译,哪个的定义放在前面,就用哪个。
然后,在代码阶段和编译阶段,在具体的每个cpp中,各自只能看到对应的那个结构体定义,所以可以访问对应的数据和函数成员。
但是,在运行时,就是未定义行为了。可能会出现运行时错误,或者运行时行为不可预期。

$ g++ c.cpp main.cpp -o test
$ ./test
b.h:A
b.h:function
y:1
b.h:A
b.h:function
y:3

$ g++ main.cpp c.cpp -o test
guo@localhost:/mnt/c/mine/bugs$ ./test
a.h:A
a.h:function
x:1
y:2
a.h:A
a.h:function
x:3
y:-1921781760

2.原因

这其实是一种未定义的行为。不同的编译器的处理不同。

为什么没有报重定义错误:因为对于每个编译单元,各自独立编译,都是有效的。但是在链接成可执行文件时,就会出现歧义了,因为各自都有一个

同一类型的数据定义。

运行行为是不可预测的。

3.解决

1.如果源码可控,还是要分别独立命名,避免重复。
2.使用命名空间:如果确实需要两种不同的结构体,应该使用不同的名称或放在不同命名空间中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值