我有一些看起来像这样的代码:
class Writable {
public:
virtual void putc(const char ch) = 0;
protected:
virtual ~Writable() {};
};
class Readable {
public:
virtual char getc() = 0;
protected:
virtual ~Readable() {};
};
Run Code Online (Sandbox Code Playgroud)
注意两个虚函数.使用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
Run Code Online (Sandbox Code Playgroud)
使用方法存根替代纯虚函数再次运行它会产生:
arm-none-eabi-size --format=berkeley bareCortexM.elf
text data bss dec hex filename
47340 2296 304 49940 c314 bareCortexM.elf
Run Code Online (Sandbox Code Playgroud)
这种巨大的差异似乎是由于例外.有什么方法可以防止这种情况发生吗?
这篇博客文章对此进行了描述:在裸机上使用C++的较小二进制大小(g ++)
提供
__cxa_pure_virtual()
实施如果您在任何地方使用纯虚函数但禁用了异常,您可能会注意到您的代码突然再次膨胀.
这发生在我身上,需要一段时间才能追踪,哎呀!
检查最终二进制文件的汇编列表(从objdump -h -C -S
),看起来好像回来了!我试过的一件事就是链接
-nostdlib
,完全将libstdc ++拉出图片.我提供了malloc,realloc,free和我使用过的一些其他stdlib函数的虚拟实现,但后来却avr32-g++
抱怨我之前没见过的东西:我失踪了__cxa_pure_virtual()
." 啊哈,"我想," 这必须是它!"在libstdc ++中找到的特定函数的源代码是一个调用
std::terminate()
,在这里看到.那个电话在我可怜的AVR32的闪存中引发了一个可爱的派对,-fno-exceptions
在他们的路上踩踏 .无论如何,
__cxa_pure_virtual()
当你调用一个纯虚函数时,它实际上是被调用的.喜欢new
和delete
,这可能是你想要覆盖的东西,所以你自己的调试/跟踪代码可以给你有用的反馈.实现很简单,只要确保它extern "C"
的名称不会被破坏:Run Code Online (Sandbox Code Playgroud)extern "C" void __cxa_pure_virtual() { while(1); }