6

我有一些看起来像这样的代码:

class Writable {
public:
    virtual void putc(const char ch) = 0;
protected:
    virtual ~Writable() {};
};

class Readable {
public:
    virtual char getc() = 0;
protected:
    virtual ~Readable() {};
};

注意两个虚函数。编译这个(连同我的其他代码)使用arm-none-eabi-gcc,并链接-fno-exceptions产生这个输出:

arm-none-eabi-size  --format=berkeley bareCortexM.elf
   text    data     bss     dec     hex filename
 108948    2304    2372  113624   1bbd8 bareCortexM.elf

用方法存根代替纯虚函数再次运行它会产生:

arm-none-eabi-size  --format=berkeley bareCortexM.elf
   text    data     bss     dec     hex filename
  47340    2296     304   49940    c314 bareCortexM.elf

这种巨大的差异似乎是由于例外。有什么办法可以防止这种情况发生吗?

4

2 回答 2

8

这篇博文对此进行了描述:Smaller binary size with C++ on baremetal (g++)

提供一个__cxa_pure_virtual()实现

如果你在任何地方使用纯虚函数但禁用了异常,你可能会注意到你的代码突然又膨胀了。

这发生在我身上,花了一段时间才找到,哎呀!
检查最终二进制文件的汇编列表(来自objdump -h -C -S),看起来异常又回来了!

我尝试过的一件事是与 链接-nostdlib,完全将 libstdc++ 排除在外。我提供了 malloc、realloc、free 和其他一些我使用的 stdlib 函数的虚拟实现,但随后avr32-g++ 抱怨了一些我以前从未见过的东西:我丢失了 __cxa_pure_virtual().

“<em>啊哈,”我想,“<em>这就是它!” 在 libstdc++ 中找到的该特定函数的源代码中,是对 的调用 std::terminate(),请参见此处。那个电话在我可怜的 AVR32 的闪存中引发了一场可爱的派对, -fno-exceptions在他们进来的路上践踏。

无论如何,__cxa_pure_virtual()当您调用纯虚函数时实际调用的是什么。就像newand一样delete,这可能是您无论如何都想要覆盖的东西,因此您自己的调试/跟踪代码可以为您提供有用的反馈。实现很简单,只要确保extern "C"名称不会被破坏:

extern "C" void __cxa_pure_virtual() { while(1); }
于 2013-02-04T15:12:08.310 回答
0

我有同样的问题,但实现__cxa_pure_virtual对我没有帮助。

但对我来说,解决方案是在-fno-exceptions选项旁边添加-fno-rtti 。

于 2014-09-08T10:44:14.660 回答