我正在为我的大学开展一个小组高级项目,在尝试让我的代码运行时遇到了一个重大障碍。

我们的 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)一旦我为对象分配了空间,就分配并找到一些技巧来调用对象的构造函数。放置 new 不是一个选项,因为 new 不是运算符。3)只要用C就可以了,它是一个微控制器,为什么我会喜欢它?4)找到一个更好的编译器,这可能会花费$$$。

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

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

有帮助吗?

解决方案

只是为了记录在案,在一个对象零位不会影响析构函数是否被调用(除非编译器有一个特殊的怪癖,使这种行为)。只要写在你的析构函数中的一些记录语句测试了这一点。

构建你的程序不分配任何东西可能是系统设计的方式。我没有与嵌入式系统工作过,但我已阅读,鼓励使用动态内存,因为运行时环境具有稀缺数额它的一些经验丰富的嵌入式商店。


不过,如果你一定要,你仍然可以使用新的位置。如果你没有<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() { }

粘在由每个源文件包括一个标题文件的某个地方使用放置新/删除。

,测试此示例文件:

#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();
}

在我的版本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;
}

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

祝你好运!

其他提示

不打你的工具。如果你有你的嵌入式系统仅有的编译器是C编译器,学习C - 这并不困难。努力生产出两种语言的一些bastardised版本正好解决了一个相当简单的编程问题仅会 结束在流泪。

要看看它的另一种方式,如果你的嵌入式平台甚至不支持C编译器,但只有一个汇编程序,将你的第一个冲动是坐下来写汇编C ++编译器?我希望不会,我希望你,而不是坐下来学习使用 汇编完成你的任务 - 编写C ++编译器(或者甚至是C编译器)是完全不恰当的利用你的时间,并且几乎肯定会导致失败。

我想你是从低于最佳的视点接近的问题。

您正专注于编译器(或其缺乏)的闷头硬件。

最有可能的答案,你的主要问题是“因为硬件不支持所有的C ++的东西”。嵌入式硬件(microcontrolers)是指出硬件设计的定制 - 存储器映射,中断处理程序,I / O等

在我看来,你应该先花一些时间与硬件书的微控制器,学习设备的来龙去脉 - 即它是如何设计和什么主要目的。一些被设计用于快速存储器操作,有的为快速I / O处理,一些用于A / d类型的工作,一些用于信号处理。该型微控制器的决定,他们为它写了汇编指令,并规定了任何更高级别的编译器可以有效地完成。

如果这是重要的,花一些时间来看看汇编以及 - 它会告诉你什么是设计师认为是重要的。它还会告诉你很多多少,你可以从一个高层次的编译器得到的。

通常,微控制器不支持C ++,因为设计确实不关心对象或花式内存处理(从C ++的角度)。这是可以做到的,但你常常试图砸向一个方孔圆形的PEG来获得构造函数和析构函数(和“新”和“删除”)在微环境中工作。

如果您有此单元C编译器,认为这是一个祝福。一个好的C编译器往往是“绰绰有余”创造优良的嵌入式软件。

干杯,

-Richard

只是因为它不具备这些工具并不意味着你不能在C ++中获益。如果项目足够大,单靠获得面向对象的设计可能是足够的动机。

如果它不支持“新”,那么这可能是因为它没有任何意义,使堆和栈之间的自动区分。这可能是因为您的内存配置。这也可能是因为内存资源,所以只约束非常小心分配有意义。如果你绝对要实现自己的“新”经营者,你可能会考虑调整 Doug Lea的malloc的。我相信,他开始了他在类似的情况下分配(重新实现的新的C ++)。

我爱STL,但它仍然可以做有用的东西,没有它。根据项目的范围,你可能会更好只使用一个数组。

我有一个类似编译器实现的嵌入式-C ++标准的奇异版本。我们有operator new这将调用构造函数,我们和析构函数被称为的在大多数情况下的。编译器/运行时供应商去,并使用trycatch作为的方便了工程师实施setjmplongjmp。问题是,他们从来没有提到,throw不会引起调用本地对象的析构函数!

总之,我们的组继承代码库后有人写作用就像是一个应用程序的标准C ++:使用RAII技术和所有其他善。我们结束了在什么一些我们称之为的重写它的面向对象的C ^ 的代替。你可能要考虑只是咬咬牙直C.相反构造的写作,有一个明确的叫做初始化方法。析构函数成为一个显式调用终止方法。没有太多的C ++,你也不会在C很快模仿的。是的,MI是在一种痛苦......但单继承是很容易的。看看的一些想法这个PDF 。这几乎说明了我们采取的方法。我真的希望我写我们的方法在某处...

您可能会发现在我的 A *教程网站一些有用的代码。虽然我写来支持这个代码使用STL的应该是易剥离的STL支持出来。此外,还有包括它(fsa.h),我写了加快STL游戏机上的一池分配器。这是C ++代码,但我把它移植最初是从C和我不认为这将是很难做到这一点的其他方式。该代码是由超过10,000人,所以这是一个很好的基础,从开始测试。

更换我使用的STL结构是没有问题的,因为它被限制为载体。我用使用堆函数(make_heap和push_heap)的向量作为一个优先级队列中的一个。您可以替换我的旧的C代码用C应该只是下降到你的代码中实现。 (只做一个页头,这样你就可以用一个指针,你的记忆的保留区域替换。

可以在从报头的代码片段看到,在C代码的主要区别是,没有这个指针,没有对象,因此您的代码通常需要一对象的指针作为第一个参数。

void PQueueInitialise( PQUEUE *pq, int32 MaxElements, uint32 MaxRating, bool32 bIsAscending );
void PQueueFree( PQUEUE *pq );
int8 PQueuePush( PQUEUE *pq, void *item,  uint32 (*PGetRating) ( void * ) );
int32 PQueueIsFull( PQUEUE *pq );
int32 PQueueIsEmpty( PQUEUE *pq );
void *PQueuePop( PQUEUE *pq, uint32 (*PGetRating) ( void * ) );

为什么不先写在您的桌面计算机上,考虑到编译器的限制,调试它,确保它完美的作品,然后才迁移到嵌入式环境?

在做嵌入式工作的时候,有一次我甚至不能链接C运行时内存的限制,但硬件有DMA(动态内存分配)的指令,所以我写了我自己的malloc与硬件,您的硬件可能有类似功能,让你可以写一个malloc,然后一个新的基于malloc的。

反正到底我用99次%堆栈分配,和一些限制设置,我将回收,通过在适当位置builiding OS的静态对象。这可能我一个很好的解决方案。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top