C++/GCC - 文件范围对象的构造函数没有被调用

标签 c++ gcc constructor initialization

我开始为 Renesas RZ/A1L 微 Controller 进行开发。 Renesas 提供了一个 IDE(e2 Studio - Eclipse 的修改版本),设置为使用 GCC 编译 C/C++。一切正常,但是......

如果我在文件范围内(在任何函数之外)声明一个对象,它的构造函数永远不会被调用。例如:

class NewClass {
public:
    int i;
    NewClass() {
        i = 4;
    }
};


NewClass newInstance;

int main(void)
{
    // My program...
}

我可以看出构造函数没有被调用,因为使用 Renesas 提供的在线调试设置,我可以看到 i 从未设置为 4(即使我进一步引用 newInstance 和 i;我也关闭了优化)。抱歉,我无法简单计算 i 的值 - 代码正在微 Controller 中运行,我还没有弄清楚如何做到这一点。

如果我改为将 NewClass newInstance; 行放在 main() 中,那么问题就会消失。

这个问题的另一个后果是,对于继承类,调用一个虚函数(通过基类类型的指针)会导致崩溃——我怀疑是由于构造函数没有执行,因此没有写入内存对象是什么类的一些指标。

通常通过什么机制调用这样的构造函数?我做了一些谷歌搜索 - 它会是“.ctors”列表吗? ( https://gcc.gnu.org/onlinedocs/gccint/Initialization.html )

Renesas 的"template"C++ 项目实际上包含调用所有 ctors 的代码;然而,通过查看我为该项目生成的 .map 文件,我可以看到实际上没有 ctors 存在。这是否缩小了问题的范围 - GCC 编译器是否没有在应该的时候吐出它们?

非常感谢您的帮助。

最佳答案

引用 C++11 标准草案 N3337,我们发现:

[basic.start.main]/1 A program shall contain a global function called main, which is the designated start of the program. It is implementation-defined whether a program in a freestanding environment is required to define a main function. [ Note: In a freestanding environment, start-up and termination is implementation-defined; start-up contains the execution of constructors for objects of namespace scope with static storage duration; termination contains the execution of destructors for objects with static storage duration. — end note ]

如您所见,它是在独立环境中实现定义的。因此,假设您有一个 32 位 x86 GCC 工具链...


这听起来像是在一个独立的环境中。如果是这样,如果您想使用全局构造函数,则需要实现一些样板文件。您链接的初始化页面提到了一个链接器行,看起来像这样:

i686-elf-ld crt0.o crti.o crtbegin.o foo.o bar.o crtend.o crtn.o

假设foo.obar.o是您程序的一部分,要求您的链接器行看起来像这样。请注意,编译器应提供自己的 crtbegin.ocrtend.o , 所以你可以找到那些使用 -print-file-name 的人的位置.在 Makefile 中,它看起来像这样:

CRTBEGIN_OBJ:=$(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ:=$(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)

现在是实际的初始化函数。在与内核入口点相同的文件中,调用 _init之前 kernel_main (或者不管它叫什么。)可选_fini可以在kernel_main之后调用但这不太可能是必要的。确切的代码将取决于体系结构,但这里是 32 位 x86 的示例:

/* x86 crti.s */
.section .init
.global _init
.type _init, @function
_init:
    push %ebp
    movl %esp, %ebp
    /* gcc will nicely put the contents of crtbegin.o's .init section here. */

.section .fini
.global _fini
.type _fini, @function
_fini:
    push %ebp
    movl %esp, %ebp
    /* gcc will nicely put the contents of crtbegin.o's .fini section here. */

/* x86 crtn.s */
.section .init
    /* gcc will nicely put the contents of crtend.o's .init section here. */
    popl %ebp
    ret

.section .fini
    /* gcc will nicely put the contents of crtend.o's .fini section here. */
    popl %ebp
    ret

关于C++/GCC - 文件范围对象的构造函数没有被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32807964/

相关文章:

c++ - 编译器如何翻译后缀/前缀运算符?

c++ - gcc -O3 标志导致 -Winline "call is unlikely and code size would grow"警告

c++ - Qt 4.6 和 4.7 之间 QString 类的变化

c# - 在显式构造函数之外初始化字段是不好的做法吗

c++ - 具有自定义哈希函数 (_bstr_t) 的无序映射仅适用于默认构造函数(重复键)

c++ - 数组中第 k 个最大的元素

c++ - Windows xp 上的 Mutex 给出 0xC0000096 : Privileged instruction exception

c - 在 xcode 中运行 c 什么也没显示

c++ - gcc:开关或 pragma 以抑制非空指针的 "%p"格式警告?

c++ - 为类构造函数中的指针分配内存