Operator new for Arduino

2019-02-19 10:19发布

问题:

I've been told (specifically in an answer to C++ Standard Library on Arduino, and in Stack Overflow question C++ string and Arduino String. How to combine them?)) that the Arduino compiler does not implement the new operator. However, I've written a program for the Arduino (in the Arduino IDE) which uses it, and it works perfectly.

void setup() {
    Serial.begin(9600);
}

void loop() {
    char* array;
    char c;
    unsigned arraySize;

    Serial.write("Enter a 1 digit number.\n");

    do {
        c = Serial.read();
    } while(c < '0' or c > '9');
    arraySize = c-'0';

    Serial.write("You wrote ");
    Serial.write(c);
    Serial.write(".\n");
    Serial.write("Now enter ");
    Serial.write(c);
    Serial.write(" lower-case letters.\n");

    array = new char[arraySize];

    for (unsigned i = 0; i < arraySize;) {
        array[i] = Serial.read();
        if (array[i] >= 'a' and array[i] <= 'z')
            i++;
    }

    Serial.write("You entered: ");

    for (unsigned i = 0; i < arraySize; i++) {
        Serial.write(array[i]);
        Serial.write(" ");
    }
    Serial.write("\n");
}

Here is a sample output to demonstrate its functionality:

Enter a 1 digit number.
You wrote 5.
Now enter 5 lower-case letters.
You entered: h e l l o
Enter a 1 digit number.
You wrote 9.
Now enter 9 lower-case letters.
You entered: w a s s u p m a n
Enter a 1 digit number.
You wrote 9.
Now enter 9 lower-case letters.
You entered: h o w y a d o i n
Enter a 1 digit number.
You wrote 4.
Now enter 4 lower-case letters.
You entered: c o o l
Enter a 1 digit number.
You wrote 7.
Now enter 7 lower-case letters.
You entered: i t w o r k s
Enter a 1 digit number.

So why do I keep hearing this? Are these people wrong, or do I simply misunderstand their meaning?

回答1:

new and delete is defined as part of the Arduino distribution: /usr/share/arduino/hardware/arduino/cores/arduino/new.h:

/* Header to define new/delete operators as they aren't provided by avr-gcc by default
   Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453 
 */
#ifndef NEW_H
#define NEW_H

#include <stdlib.h>

void * operator new(size_t size);
void operator delete(void * ptr); 

__extension__ typedef int __guard __attribute__((mode (__DI__)));

extern "C" int __cxa_guard_acquire(__guard *);
extern "C" void __cxa_guard_release (__guard *);
extern "C" void __cxa_guard_abort (__guard *); 

extern "C" void __cxa_pure_virtual(void);

#endif

The new.h is included in Printable.h so you are getting it in your Arduino basic includes. These operators are not defined in AVR Libc though. My interpretation of these design choices: the Libc people thought it was a bad idea, whereas Arduino people are all about ease of use: if you want new and delete, please have them.



回答2:

As you’ve demonstrated, new and delete do work in principle on Arduino. The problem is that your Arduino has 2K of RAM for global variables, stack, and heap combined, so any substantial program you write for it has to be highly aware of memory usage.

Therefore, for an embedded system like this, it is generally preferable to use static allocation (or possibly per-class dynamic allocation in some situations) rather than general purpose dynamic allocation: For simple programs, you don’t need dynamic allocation, and for complex programs, you can’t afford it.



回答3:

Just because the platform doesn't predefine operator new() doesn't mean that you can't define it. In your code, presumably someone will have written a definition for the allocation function, so all is well.

(I assume you're familiar with the difference between the new expression and the allocation function, which is confusingly called operator new().)


Here's a baby example definition that should get a short program going:

char buf[1024];
char * cur = buf;

void * operator new(std::size_t n)
{
    char * res = cur;
    std::size_t inc = (n + 15) / 16 * 16;

    if (std::distance(cur, buf + sizeof(buf)) < inc)
        throw std::bad_alloc();

    cur += inc;

    return res;
}

void operator delete(void * p) noexcept
{
}

This will obviously run out of memory very fast.