我有一个运行裸机的C ++应用程序,我希望尽可能小。
我没有在任何地方使用动态内存分配。我没有使用STL功能。我还用空函数覆盖了所有“delete”和“new”的变种。尽管如此,当我查看符号的排序列表时,我发现malloc()仍然是我编译的二进制文件中最大的项目之一。如果我能摆脱它,我可以将我的二进制缩小约25%。
C ++运行时通常需要malloc()来进行幕后类型的工作吗?
(我正在使用Xilinx的gcc前缀用于Microblaze架构,如果这很重要的话)
答案 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
的名称。然后,请勿使用new
,std::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列出了ciso646
,cstddef
,cfloat
,limits
,climits
,cstdint
,cstdlib
,{{ 1}},new
,typeinfo
,exception
,initializer_list
,cstdalign
,cstdarg
,cstdbool
和{{1 }}
以上大多数标题包含类型,常量和模板的简单定义。唯一可能有问题的是type_traits
,atomic
,typeinfo
和exception
。前两个分别支持RTTI和异常,您可以确保使用其他编译器标志禁用它们。您可以通过不调用cstdlib
/ new
而不使用cstdlib
表达式来忽略new
和exit
。避免at_exit
的原因是它可能会在内部调用new
。独立片段中的任何其他内容都不应在at_exit
或new
中调用任何内容。
选项
上面最重要的选项是cstdlib
,可让您控制程序启动时的运行情况。
new
告诉编译器和标准库(而不是它的独立片段)不要假设整个标准库存在(即使它仍然存在)。它可能会阻止生成令人惊讶的代码。请注意,此选项实际上并未限制您可用的标头。例如,您仍然可以使用-e _entry
,但如果您也更改了入口点,则可能不是一个好主意。它的作用是阻止支持独立标头的代码调用独立标头之外的任何内容,并防止编译器隐式生成任何此类调用。
答案 2 :(得分:0)
如果您使用任何STL
,例如std::lib
或std::map
。甚至std::cout
,场景后面都会有动态内存分配。
答案 3 :(得分:-1)
它总是需要malloc。因为必须加载二进制文件以及共享库。