当嵌入式编译器没有运算符new或STL支持时,如何进行C++?

Ber*_*iri 6 c c++ embedded microcontroller memory-management

我正在为我的大学开展一个小组高级项目,并且在尝试使我的代码工作时遇到了一个主要障碍.

我们为8位Atmel微控制器提供的编译器不支持new或delete运算符,并且它不支持C++ STL.我可以用C编程,但是我必须实现一个我从未做过的A*算法.虽然我最初尝试过C,但我很快意识到我以前从未做过纯C.尝试使用结构和函数对对象进行建模正在减慢我的速度,因为我已经习惯了更清晰的C++语法.

无论如何,我的编译器缺点的确切措辞可以在这里找到:http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus

为了克服它们并仍然使用C++,我考虑了以下可能性.1)不要分配任何东西,只需使用模板在堆栈上生成固定数组.2)在为对象分配空间后,分配并找到一些hack来调用对象的构造函数.由于new不是运营商,因此不能选择新的展示位置.3)只需使用C并将其吸收,它是一个微控制器为什么我会变得喜欢?4)找到一个更好的编译器,可能会花费$$$.

第二种选择是最难的,但就我如何编写这段代码而言,它将获得最大的回报.但是,我想如果我弄错了调试它可能是一个巨大的痛苦.我正在考虑在堆栈上创建对象,将它们的位复制到分配的空间中,然后将对象中的位清零,这样它就不会调用它的析构函数.为此,我将使用unsigned char指针和sizeof运算符直接访问这些位以获取字节数.

这听起来很糟糕,我不知道它是否可以正常工作,但我正在考虑它.我知道vtable可能有问题,但我不打算使用任何vtable,因为它只是一个8位微控制器.

小智 23

不要打你的工具.如果您的嵌入式系统唯一的编译器是C编译器,那么学习C - 这并不困难.为了解决一个相当简单的编程问题,试图生成两种语言的一些混合版本只会流下眼泪.

换一种方式来看,如果您的嵌入式平台甚至不支持C编译器,而只支持汇编程序,那么您的第一个冲动是坐下来在汇编程序中编写C++编译器吗?我希望不会,我希望你能坐下来学习使用汇编程序来完成你的任务 - 编写一个C++编译器(甚至是一个C编译器)将完全不恰当地利用你的时间,几乎肯定会导致失败.


Chr*_*ung 10

只是为了记录,将对象中的位置零将不会影响析构函数是否被调用(除非编译器具有启用此行为的特殊怪癖).只需在析构函数中编写一些日志语句来测试它.

构建程序不分配任何东西可能就是系统的设计方式.我之前没有使用嵌入式系统,但是我已经阅读了一些经验丰富的嵌入式商店,这些商店不鼓励使用动态内存,因为运行时环境的数量很少.


但是,如果必须,您仍然可以使用新的展示位置.如果你没有<new>标题,这里是我的GCC版本中直接来自它的相关行:

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

// Default placement versions of operator delete.
inline void  operator delete  (void*, void*) throw() { }
inline void  operator delete[](void*, void*) throw() { }
Run Code Online (Sandbox Code Playgroud)

将其粘贴在使用放置新/删除的每个源文件所包含的头文件中.

测试这个的示例文件:

#include <cstdio>
#include <new>

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    char foobar[16];
    cstr* str = new (&foobar) cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    str->~cstr();
}
Run Code Online (Sandbox Code Playgroud)

在我的GCC版本中,根本不使用libstdc++(如果-fno-exceptions使用的话).


现在,如果你想将它与malloc(如果你的平台提供)相结合,那么你可以这样做:

#include <cstdio>
#include <cstdlib>

inline void* operator new  (std::size_t n) {return std::malloc(n);}
inline void* operator new[](std::size_t n) {return std::malloc(n);}
inline void  operator delete  (void* p) {std::free(p);}
inline void  operator delete[](void* p) {std::free(p);}

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    cstr* str = new cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    delete str;
}
Run Code Online (Sandbox Code Playgroud)

这允许您使用您熟悉的标准new/ delete,而无需使用libstdc++.

祝好运!


Hun*_*ods 6

我认为你从一个不太理想的观点来看待这个问题.

您专注于编译器(或缺乏编译器)而不是专注于硬件.

对你的主要问题最可能的答案是"因为硬件不支持所有C++的东西".嵌入式硬件(微控制器)以硬件设计的定制而着称 - 存储器映射,中断处理程序,I/O等.

在我看来,你应该花一些时间在微控制器的硬件书上,学习设备的细节 - 即它是如何设计的,主要用途是什么.一些设计用于快速存储器操作,一些用于快速I/O处理,一些用于A/D类型工作,一些用于信号处理.微控制器的类型规定了他们为其编写的汇编器指令,并指示任何更高级别的编译器可以有效地执行什么操作.

如果这很重要,那么花点时间看一下汇编程序 - 它会告诉你设计师认为重要的东西.它还会告诉您很多关于从高级编译器可以获得多少的信息.

通常,微控制器不支持C++,因为设计实际上并不关心对象或花哨的内存处理(从C++的角度来看).它可以做到,但是你经常试图在一个方孔中敲一个圆钉以使构造函数和析构函数(以及'new'和'delete')在微环境中工作.

如果你有一个C编译器为这个单位,考虑它是一个祝福.一个好的C编译器通常"绰绰有余"来创建出色的嵌入式软件.

干杯,

-Richard