C ++运行时总是需要malloc()吗?

时间:2015-05-16 04:25:17

标签: c++ malloc xilinx standard-library bare-metal

我有一个运行裸机的C ++应用程序,我希望尽可能小。

我没有在任何地方使用动态内存分配。我没有使用STL功能。我还用空函数覆盖了所有“delete”和“new”的变种。尽管如此,当我查看符号的排序列表时,我发现malloc()仍然是我编译的二进制文件中最大的项目之一。如果我能摆脱它,我可以将我的二进制缩小约25%。

C ++运行时通常需要malloc()来进行幕后类型的工作吗?

(我正在使用Xilinx的gcc前缀用于Microblaze架构,如果这很重要的话)

4 个答案:

答案 0 :(得分:4)

在{C}和C ++中,malloc()上的程序的依赖性可能会发生,即使程序不直接使用它们也是如此。它是编译器和标准库的实现质量,而不是标准的要求。

这实际上取决于编译器启动代码(可以调用main()所设置的代码)的工作原理以及标准库代码的实现方式。

例如,在C和C ++中,启动代码(在托管环境中)需要收集有关命令行参数的信息(可能复制到某个已分配的缓冲区),连接到标准文件/流(如std::cout和C ++中的std::cin和C中的`stdout和stdin)。任何这些事情都可能涉及动态内存分配(例如,与标准流相关的缓冲区)或执行程序实际不需要的代码。

答案 1 :(得分:2)

C ++有两种实现方式:托管和独立。托管实现确实假设存在malloc并且经常将其用于内部目的。独立实现假设只存在new函数,因为它支持C ++关键字new,但很容易确保此函数不被调用。

两者之间的区别在于,在独立实现中,您可以控制程序启动,并且所需的标头和库集是有限的。通过设置入口点来控制程序启动。

g++ -ffreestanding -e _entry program.cpp

program.cpp可能是:

extern "C" int entry()
{
    return 0;
}

extern "C"是防止C ++名称重整的必要条件,这可能会使链接期间很难弄清entry的名称。然后,请勿使用newstd::string,流I / O,STL等,并避免使用at_exit

这可以让您控制启动和清理代码,并限制编译器可以隐式依赖标准库提供的内容。但请注意,这可能是一个具有挑战性的环境。您不仅会阻止堆,I / O流等的初始化,还会阻止异常,RTTI的设置以及静态存储对象构造函数的调用等。您必须编写代码或使用库来手动选择您可能想要使用的C ++的几个功能。如果你走这条路,你可能想要仔细阅读这个wiki http://wiki.osdev.org/C%2B%2B。您可能希望至少调用全局构造函数,这很容易。

说明

标准

C ++有一个"独立实现"的概念,其中可用的标头更少。

3.6.1主要功能[basic.start.main]

  

1 [snip]是实现定义的,是否需要独立环境中的程序来定义主函数。

17.6.1.3独立实施[合规]

  

1定义了两种实现:托管和独立(1.4)。对于托管实现,这个   国际标准描述了可用标题集。

     

2独立实现具有一组实现定义的头。该套装至少应包括   标题如表16所示。

     

3提供的标题版本< cstdlib>应至少声明函数abort,atexit,at_quick_exit,exit和quick_exit(18.5)。 [剪断]

表16列出了ciso646cstddefcfloatlimitsclimitscstdintcstdlib,{{ 1}},newtypeinfoexceptioninitializer_listcstdaligncstdargcstdbool和{{1 }}

以上大多数标题包含类型,常量和模板的简单定义。唯一可能有问题的是type_traitsatomictypeinfoexception。前两个分别支持RTTI和异常,您可以确保使用其他编译器标志禁用它们。您可以通过不调用cstdlib / new而不使用cstdlib表达式来忽略newexit。避免at_exit的原因是它可能会在内部调用new。独立片段中的任何其他内容都不应在at_exitnew中调用任何内容。

选项

上面最重要的选项是cstdlib,可让您控制程序启动时的运行情况。

new告诉编译器和标准库(而不是它的独立片段)不要假设整个标准库存在(即使它仍然存在)。它可能会阻止生成令人惊讶的代码。请注意,此选项实际上并未限制可用的标头。例如,您仍然可以使用-e _entry,但如果您也更改了入口点,则可能不是一个好主意。它的作用是阻止支持独立标头的代码调用独立标头之外的任何内容,并防止编译器隐式生成任何此类调用。

答案 2 :(得分:0)

如果您使用任何STL,例如std::libstd::map。甚至std::cout,场景后面都会有动态内存分配。

答案 3 :(得分:-1)

它总是需要malloc。因为必须加载二进制文件以及共享库。