C++ 全局对象初始化失败——为什么?是否可以将对象放入 .DATA 部分?

C++ global object initialization fails -- why? and is it possible to put objects in .DATA section?

我在微控制器上使用 C 已经有一段时间了。

最近(终于!)我设法让 GCC 为我的 µC 编译了一些 c++ 代码,并开始移植一些以前只是 "simulating" OOP 的代码到真正的交易中。

经过长时间的调试、挣扎和谷歌搜索,我只剩下一个问题,但这个问题让我很困惑。 运行 此代码 (GCC/Arm):

class Test {                                                                              

public:
    int val;

    Test( int val ){                                                                      
        this->val = val;                                                                  
    }
};

Test test1( 5 );                                                                          

static void _test() {

    Test test2( 7 );                                                                      

    Debug::printf( "-test1: %d-\n", test1.val );                                          
    Debug::printf( "-test2: %d-\n", test2.val );
}

int main() { _init(); /*Hardware*/ _test(); while(1){} } 

我得到输出:

-test1: 0-
-test2: 7-

所以不知何故 test1 没有像我预期的那样被初始化。

为什么会这样?这里到底发生了什么?(编译器为什么不抱怨?)

我想做什么:因为这是微控制器上的运行,所以我想避免使用"malloc/new",而是把它放在.DATA 部分,就像我使用C:

struct Test {
    int val;
}

Test test1 = { 5 };

这可能吗?

So somehow test1 doesn't get initialized as I would have expected it to be.

初始化顺序是您在全局范围内创建变量时要处理的一个问题。避免这个问题的一种方法是用访问函数封装它们。

下面的代码应该独立于全局对象的初始化顺序工作,因为它不依赖于全局对象。

static Test& getTest1()
{
   static Test t(5);
   return t;
}                                                                          

static void _test() {

    Test test2( 7 );                                                                      

    Debug::printf( "-test1: %d-\n", getTest1().val );                                          
    Debug::printf( "-test2: %d-\n", test2.val );
}

使用普通的 structclass 确实是可能的:

class Test { // or use struct without explicit public accessibility
public:
    int val;
};

Test  test1 = { 5 };

你:

  • 无法使用这种简单的布局进行任何花哨的建筑工作,并且
  • 不能有任何需要构造的成员。

否则,如果您按照示例中的方式进行编程,则无需担心 newmalloc:即使构造函数是打电话。

附带说明:在使用构造函数时考虑使用初始化列表:

class Test {
  int  m_val;
public:
  Test(int  val) : m_val(val) {}
};

在嵌入式系统编程中,依靠构造函数调用具有静态存储持续时间的对象是非常糟糕的做法。

这是因为很多编译器都有创建非标准的选项"minimal startup",这意味着编译器将忽略 C 和 C++ 标准的要求并跳过静态的所有初始化存储持续时间变量,包括为此类对象调用构造函数

此外,在一般的 C++ 中,您必须注意不要依赖静态存储持续时间变量的初始化顺序。如果你有对象A和B,并且对象A先被初始化,那么在A的构造函数中不能有任何依赖于B被初始化的代码。 More info in the C++ FAQ.