相关疑难解决方法(0)

外部变量只在标题中意外工作,为什么?

我目前正在为Arduino更新一个C++库(特别是使用avr-gcc编译的8位AVR处理器).

通常,默认Arduino库的作者喜欢在头文件中包含类的extern变量,该变量也在类.cpp文件中定义.我假设这基本上是为了让新手作为内置对象准备好了.

我的方案是:我更新的库不再需要.cpp文件,我已将其从库中删除.直到我最后一次检查我发现的错误,我才发现没有链接器错误,尽管事实上没有为extern.cpp文件中的变量提供定义.

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

struct Foo{
  void method() {}
};

extern Foo foo;
Run Code Online (Sandbox Code Playgroud)

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

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

在发现这一点后,我发现其重要的是要注意:

  • 类函数只返回其他对象,就像在运算器中返回对自身的引用,甚至是副本一样.
  • 它只修改外部对象(volatile uint8_t代码中有效引用的寄存器),并返回其他类的临时对象.
  • 此标题中的所有类函数都是如此基本,以至于它们的成本低于或等于函数调用的成本,因此它们(在我的测试中)完全内联到调用者中.典型的语句可能会在调用链中创建许多临时对象,但是编译器会通过这些查找并直接输出有效的代码修改寄存器,而不是一组嵌套的函数调用.

我还记得读n3797 7.1.1 - 8extern可以在不完全类型使用,但是类完全定义,而申报是不是(这可能是无关紧要的).

我被引导相信这可能是游戏优化的结果.我已经看到了获取地址对对象的影响,否则这些对象将被视为常量并且在没有使用RAM的情况下进行编译.通过向编译器无法保证状态的对象添加任何间接层,将导致此RAM消耗行为.

所以,也许我只是通过询问就回答了我的问题,但是我仍然在做假设并且困扰我.经过相当长一段时间的爱好编码C++,字面意思是我的do-not列表中唯一的东西就是做出假设.

真的,我想知道的是:

  • 关于我的工作解决方案,是否记录了无法获取类的地址(导致间接)的简单情况?
  • 它只是由优化引起的边缘情况行为,消除了对某些内容的需求吗?
  • 或者是简单明了的未定义行为.因为在GCC中可能有一个错误并允许在优化降低或禁用时可能失败的代码?

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

这是我的第一个问题,所以如果您想了解某些细节,请告诉我.如果需要,我还可以提供GitHub链接.

编辑:由于库需要与现有代码兼容,我需要保持使用点语法的能力,否则我只需要一类静态函数.

为了删除现在的假设,我看到两个选项:

  • 仅为变量声明添加.cpp.
  • 在标题中使用define,就像#define foo (Foo())通过临时允许点语法一样.

我更喜欢使用定义的方法,社区的想法是什么?

干杯.

c++ avr-gcc

6
推荐指数
1
解决办法
635
查看次数

标签 统计

avr-gcc ×1

c++ ×1