C++ 运行时是否总是需要 malloc()?
Does C++ runtime always require malloc()?
我有一个 C++ 应用程序 运行 裸机,我想使其尽可能小。
我没有在任何地方使用动态内存分配。我没有使用任何 STL 函数。我还用空函数覆盖了 "delete" 和 "new" 的所有变体。尽管如此,当我查看经过排序的符号列表时,我发现 malloc() 仍然是我编译的二进制文件中最大的项目之一。如果我能摆脱它,我可以将我的二进制文件缩小大约 25%。
C++ 运行时是否通常需要 malloc() 进行幕后类型工作?
(我正在为 Microblaze 架构使用 Xilinx 的 gcc 分支,如果这很重要的话)
如果您使用任何 STL
,例如 std::lib
或 std::map
。甚至std::cout
,背后还会有动态内存分配
它总是需要malloc。因为必须加载二进制文件以及共享库。
程序对 malloc()
的依赖可能发生在 C 和 C++ 中,即使程序不直接使用它们。这是编译器和标准库的实现质量问题,而不是标准的要求。
这实际上取决于编译器启动代码(进行设置以便 main()
可以被调用的代码)的工作方式以及标准库代码的实现方式。
例如,在 C 和 C++ 中,启动代码(在托管环境中)需要收集有关命令行参数的信息(可能复制到某个分配的缓冲区),连接到标准 files/streams(如 [= C++ 中的 12=] 和 std::cin
,以及 C 中的 `stdout 和 stdin)。这些事情中的任何一个都可能涉及动态内存分配(例如,用于与标准流关联的缓冲区)或执行程序实际不需要的代码。
C++ 有两种实现方式,托管的和独立的。托管实现确实假设 malloc
存在并且经常将其用于内部目的。独立实现假定仅存在 new
函数,因为它支持 C++ 关键字 new
,但很容易确保不会调用此函数。
两者的区别在于,在独立实现中,您可以控制程序启动,所需的 headers 和库集是有限的。通过设置入口点来控制程序启动。
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 和调用静态存储 object 构造函数等。您将不得不编写代码或使用库来手动选择您可能想要使用的 C++ 的几个功能。如果你走这条路,你可能想仔细阅读这个 wiki http://wiki.osdev.org/C%2B%2B。您可能至少需要调用全局构造函数,这很容易做到。
说明
标准
C++ 有一个 "freestanding implementation" 的概念,其中可用的 headers 较少。
3.6.1 主要功能[basic.start.main]
1 [snip] It is implementation-defined whether a program in a freestanding environment is required to define a main function.
17.6.1.3 独立实施 [合规]
1 Two kinds of implementations are defined: hosted and freestanding (1.4). For a hosted implementation, this
International Standard describes the set of available headers.
2 A freestanding implementation has an implementation-defined set of headers. This set shall include at least
the headers shown in Table 16.
3 The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). [snip]
Table 16 个列表 ciso646
, cstddef
, cfloat
, limits
, climits
, cstdint
, cstdlib
, new
, typeinfo
, exception
, initializer_list
, cstdalign
, cstdarg
, cstdbool
, type_traits
, 和 atomic
.
上面的大多数 headers 包含类型、常量和模板的简单定义。唯一看起来有问题的是 typeinfo
、exception
、cstdlib
和 new
。前两个分别支持 RTTI 和异常,您可以确保使用额外的编译器标志将其禁用。 cstdlib
和 new
您可以通过不调用 exit
/at_exit
和不使用 new
表达式来简单地忽略。避免 at_exit
的原因是它可能会在内部调用 new
。独立片段中的任何其他内容都不应调用 cstdlib
或 new
.
中的任何内容
选项
上面最重要的选项是 -e _entry
,它使您可以控制程序启动时运行的内容。
-ffreestanding
告诉编译器和标准库(而不是它的独立片段)不要假设整个标准库都存在(即使它仍然存在)。它可以防止生成令人惊讶的代码。请注意,此选项实际上并不限制 您 可以使用哪些 headers。例如,您仍然可以使用 iostream
,尽管如果您还更改了入口点,这可能不是一个好主意。它的作用是阻止支持 freestanding headers 的代码调用 freestanding headers 之外的任何内容,并阻止编译器不会隐式生成任何此类调用。
我有一个 C++ 应用程序 运行 裸机,我想使其尽可能小。
我没有在任何地方使用动态内存分配。我没有使用任何 STL 函数。我还用空函数覆盖了 "delete" 和 "new" 的所有变体。尽管如此,当我查看经过排序的符号列表时,我发现 malloc() 仍然是我编译的二进制文件中最大的项目之一。如果我能摆脱它,我可以将我的二进制文件缩小大约 25%。
C++ 运行时是否通常需要 malloc() 进行幕后类型工作?
(我正在为 Microblaze 架构使用 Xilinx 的 gcc 分支,如果这很重要的话)
如果您使用任何 STL
,例如 std::lib
或 std::map
。甚至std::cout
,背后还会有动态内存分配
它总是需要malloc。因为必须加载二进制文件以及共享库。
程序对 malloc()
的依赖可能发生在 C 和 C++ 中,即使程序不直接使用它们。这是编译器和标准库的实现质量问题,而不是标准的要求。
这实际上取决于编译器启动代码(进行设置以便 main()
可以被调用的代码)的工作方式以及标准库代码的实现方式。
例如,在 C 和 C++ 中,启动代码(在托管环境中)需要收集有关命令行参数的信息(可能复制到某个分配的缓冲区),连接到标准 files/streams(如 [= C++ 中的 12=] 和 std::cin
,以及 C 中的 `stdout 和 stdin)。这些事情中的任何一个都可能涉及动态内存分配(例如,用于与标准流关联的缓冲区)或执行程序实际不需要的代码。
C++ 有两种实现方式,托管的和独立的。托管实现确实假设 malloc
存在并且经常将其用于内部目的。独立实现假定仅存在 new
函数,因为它支持 C++ 关键字 new
,但很容易确保不会调用此函数。
两者的区别在于,在独立实现中,您可以控制程序启动,所需的 headers 和库集是有限的。通过设置入口点来控制程序启动。
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 和调用静态存储 object 构造函数等。您将不得不编写代码或使用库来手动选择您可能想要使用的 C++ 的几个功能。如果你走这条路,你可能想仔细阅读这个 wiki http://wiki.osdev.org/C%2B%2B。您可能至少需要调用全局构造函数,这很容易做到。
说明
标准
C++ 有一个 "freestanding implementation" 的概念,其中可用的 headers 较少。
3.6.1 主要功能[basic.start.main]
1 [snip] It is implementation-defined whether a program in a freestanding environment is required to define a main function.
17.6.1.3 独立实施 [合规]
1 Two kinds of implementations are defined: hosted and freestanding (1.4). For a hosted implementation, this International Standard describes the set of available headers.
2 A freestanding implementation has an implementation-defined set of headers. This set shall include at least the headers shown in Table 16.
3 The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). [snip]
Table 16 个列表 ciso646
, cstddef
, cfloat
, limits
, climits
, cstdint
, cstdlib
, new
, typeinfo
, exception
, initializer_list
, cstdalign
, cstdarg
, cstdbool
, type_traits
, 和 atomic
.
上面的大多数 headers 包含类型、常量和模板的简单定义。唯一看起来有问题的是 typeinfo
、exception
、cstdlib
和 new
。前两个分别支持 RTTI 和异常,您可以确保使用额外的编译器标志将其禁用。 cstdlib
和 new
您可以通过不调用 exit
/at_exit
和不使用 new
表达式来简单地忽略。避免 at_exit
的原因是它可能会在内部调用 new
。独立片段中的任何其他内容都不应调用 cstdlib
或 new
.
选项
上面最重要的选项是 -e _entry
,它使您可以控制程序启动时运行的内容。
-ffreestanding
告诉编译器和标准库(而不是它的独立片段)不要假设整个标准库都存在(即使它仍然存在)。它可以防止生成令人惊讶的代码。请注意,此选项实际上并不限制 您 可以使用哪些 headers。例如,您仍然可以使用 iostream
,尽管如果您还更改了入口点,这可能不是一个好主意。它的作用是阻止支持 freestanding headers 的代码调用 freestanding headers 之外的任何内容,并阻止编译器不会隐式生成任何此类调用。