gpt4 book ai didi

c++ - 仅在 header 中的extern变量意外起作用,为什么?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:40:25 24 4
gpt4 key购买 nike

我当前正在更新Arduino的C++库(使用avr-gcc编译的8位AVR处理器)。

通常,默认Arduino库的作者喜欢在 header 中包含该类的extern变量,该变量也在.cpp类文件中定义。我认为基本上是为了让新手能够将所有东西都准备好作为内置对象。

我遇到的情况是:我更新的库不再需要.cpp文件,并且已将其从库中删除。直到我进行最后一遍检查发现的错误之后,尽管没有为.cpp文件中的extern变量提供定义的事实,但没有产生链接器错误。

这很简单,我可以得到它(头文件):

struct Foo{
void method() {}
};

extern Foo foo;

包含此代码并将其用于一个或多个源文件中不会导致任何链接器错误。我已经在Arduino使用的GCC的两个版本(4.3.7,4.8.1)和启用/禁用C++ 11的版本中都尝试过。

在尝试导致错误的过程中,我发现只有当执行诸如获取对象地址或修改添加的虚拟变量的内容之类的操作时,才有可能。

发现这一点后,我发现需要注意的重要事项:
  • 类函数仅返回其他对象,例如,类似于运算符返回对其自身的引用,甚至返回拷贝。
  • 它仅修改外部对象(实际上是代码中volatile uint8_t引用的寄存器),并返回其他类的临时对象。
  • 此 header 中的所有类函数都很基础,以至于它们的成本低于或等于函数调用的成本,因此(在我的测试中)它们完全内联到调用程序中。一个典型的语句可能在调用链中创建许多临时对象,但是编译器会仔细查看这些对象,并直接输出有效的代码修改寄存器,而不是一组嵌套的函数调用。

  • 我还记得 n3797 7.1.1-8 中的读物, extern可以用于不完整的类型,但是该类是完全定义的,而声明不是(这可能无关紧要)。

    我被认为可能是优化的结果。我已经看到了获取地址对对象的影响,否则该对象将被视为常量并且无需使用RAM即可进行编译。通过将任何间接层添加到编译器无法保证状态的对象,将导致此RAM消耗行为。

    因此,也许我只是问了一个问题就回答了我的问题,但是我仍然在做假设,这困扰着我。经过一段时间的业余爱好C语言编码后,从字面上看,我的 do-not 列表上唯一要做的就是假设。

    确实,我想知道的是:
  • 关于我的工作解决方案,这是一个简单的案例,它记录了无法获取该类的地址(原因是间接寻址)的方法吗?
  • 这是否只是由于优化而消除了不需要链接的东西导致的极端情况行为?
  • 还是简单明了的未定义行为。如在GCC中一样,可能存在错误,并且是否允许在降低或禁用优化的情况下失败的代码?

  • 或者,你们中的一个可能很幸运,拥有一个解码器环,该环可以在标准中找到概述具体细节的合适段落。

    这是我的第一个问题,因此,如果您想了解某些详细信息,请告诉我,如果需要,我还可以提供指向代码的GitHub链接。

    编辑:因为该库需要与现有代码兼容,所以我需要保持使用点语法的功能,否则我将只拥有一类静态函数。

    现在删除假设,我看到两个选择:
  • 为变量声明添加一个.cpp。
  • 在标题中使用#define foo (Foo())之类的定义,以允许通过临时句点的语法。

  • 我更喜欢使用定义的方法,社区对此有何看法?

    干杯。

    最佳答案

    这可能是由于优化导致的极端情况行为,或者您从不在代码中使用foo变量。我不是100%肯定这不是正式的未定义行为,但是我很确定从实际的角度来看这不是未定义的行为。
    extern变量是通过这种方式实现的,用它们编译的代码会产生所谓的重定位-应该放置变量地址的空位置-然后由链接器填充。显然,foo从未以需要获取其地址的方式在您的代码中使用,因此链接器甚至不会尝试查找该符号。如果关闭优化(-O0),则可能会出现链接器错误。

    更新:如果要保留“点表示法”但要消除未定义的外部问题,则可以将extern替换为static(在头文件中),从而为每个TU创建单独的变量“实例”。由于无论如何都会对该变量进行优化,因此这根本不会更改实际代码,但对于未优化的构建也将起作用。

    关于c++ - 仅在 header 中的extern变量意外起作用,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29098518/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com