我使用带有ARM工具集的Keil 4用于Cortex M3(如果这甚至很重要)。 我尝试了这个简单的代码:
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base
{
public:
int b;
virtual ~Derived() {}
};
如果我在本地创建一个Derived实例(在main中),一切都很好:调试工作,程序大小约为300字节。
如果我创建Derived的静态或全局实例,程序大小最多增加到1000字节,调试会话在BKPT指令上停止。
我解决了这个问题,因为堆大小设置为默认值(零)。当我添加一些堆时,调试开始起作用。
使析构函数受到保护,但非虚拟,导致相同的行为。使通常的方法虚拟没有。
所以,我的问题是:在这种情况下编译器需要堆的原因是什么?
静态创建Vtab(我检查过),全局对象也应该是静态的。当我不需要动态分配时,为堆分配代码浪费另外700个字节(以及堆本身的空间)是一种愚蠢的行为。
(我使析构函数为virtual以防止出现警告。)
答案 0 :(得分:1)
当在函数之外定义实例时,会发生两件事。首先,在调用main之前调用对象的构造函数。程序员必须小心,构造函数不会执行任何可能需要稍后进行的初始化的操作。其次,实例的内存在堆上分配,因为main之前没有本地范围。嵌入式系统程序员必须特别注意实例化全局对象。如果构造函数依赖于某些在main之前未初始化的硬件,那么可能会发生不好的事情。熟悉Keil提供的C启动文件(初始化堆后调用main的汇编语言模块,将flash复制到ram,并调用全局构造函数)。
答案 1 :(得分:0)
答案就在这里,在Keil论坛上 - http://www.keil.com/forum/21859/。原因是生成函数“__aeabi_atexit”,它从main返回后调用。这有点好笑,因为这种回归永远不会发生在嵌入式系统中。