Limitazioni compilatore

Ciao a tutti

sono nuovo del campo...

ho letto, che Arduino utilizza un compilatore GCC (comunque c++).
vorrei sapere se ci sono delle limitazioni,
perchè facento delle prove non mi diconosce il "delete", il new, ecc.

forse sto sbagliando io.
grazie per l' " AiUtINO " ...

ciao

così scritto è difficile capire il tuo problema... arduino usa di base il compilatore avr-gcc in un processo di build che è ben descritto qui:
http://arduino.cc/en/Hacking/BuildProcess

se posti lo sketch che non ti funziona possiamo capire qual'è il problema...

gli operatori new sono supportati nell'arduino UNO... o era una modifica mia? :grin:

In C++ gli opertatori sono sovraccaricabili (overload) così anche new e delete sono sovraccaricabili, quindi nulla vieta di creare delle funzioni agganciate a questi operatori. Tuttavia c'è da considerare che l'operatore new richiede una memoria "heap" che però poi deve essere gestita cioè liberata con tutto quello che comporta, per cui si è pensato di fare allocazione statica della memoria, specie perchè questa è di piccole dimensioni e solitamente si vuole sfruttare ogni byte.

Come già detto da Astro il C++ non è buono per programmare i microcontroller, tuttavia si può usare ma con delle accortezze, cioè usare sempre i tipi standard, quando necessario ridefinire un tipo standard e solo nei casi evidenti creare classi allocando le instanze staticamente.

Comunque nella versione dell'IDE 1.0 io ricordo di aver visto codice nella libreria core che implementa gli operatori new e delete, ma non so se questo codice è attivo di default.

Ciao.

comunque se non erro il GCC fa colo C puro, il C++ viene aggiunto da un modulo

il codice mi sa che è attivo, perchè io li sto usando.

uso Arduino 1.0 come IDE e AMege 2560 come Hardware

codice di esempio:

int *p_int;
int *p_a_int;

void setup()
{
  // OK
  p_int = new int;
  delete p_int;

  //errore di compilazione
  p_a_int = new int [12];
  delete[] p_a_int; 
}

il compilatore mi segnale i seguenti errori:
test.o: In function setup': C:\Users\piro_net\AppData\Local\Temp\build4977060902186031728.tmp/test.cpp:21: undefined reference to operator new(unsigned int)'
C:\Users\piro_net\AppData\Local\Temp\build4977060902186031728.tmp/test.cpp:22: undefined reference to `operator delete'

grazje:::

Ciao

stai cercando di allocare un array dinamico nel setup?

non puoi semplicemente dichiarare

int p_a_int[12];

?

ma scusa, l'operatore new e delete serve per le classi, non per i tipi di dato primitivi. in quel caso si usa la famiglia di funzioni malloc(), realloc() etc.. e free()

e poi delete non credo che esista. sempre per il fatto che un array è un tipo di dato primitivo.

ciao

no.

questo è un esempio per fare venire fuori l'errore.
il mio intento è di capire se si possono creare array dinamici.

certo che si possono fare, ma NON con gli operatori new e delete che servono per le classi.

per fare array dinamici basta il C puro con malloc() e free().

ciao

come dice lesto, gli array dinamici si creano usando le funzioni di allocazione dinamica della memoria e strutture tipo liste etc...
Ci sono anche librerie pronte per Arduino,es:
http://arduino.cc/playground/Code/QueueArray

in C++ il new si può usare anche per cheare array di primitivi.
pio con delete si dealloca la memoria.

è l’equivalente malloc e free del C
(come con malloc e free si possono allocare strutture e classi)

ho dato un occhiata alla libreria delle QueueArray
così su due piedi mi sembra un template

QueueArray queue;

programmazione ancora più spinta…

Su dei microcontrollori con qualche centinaio, o migliaio, di byte di memoria l'uso di malloc() secondo il mio modestissimo punto di vista è sconsigliato perché si rischia di frammentare la memoria e di ritrovarsi con la RAM esaurita prima del suo effettivo riempimento. Se si implementano tecniche di deframmentazione si deve creare un heap per la gestione degli spazi allocati/deallocati e di una serie di algoritmi che vanno a sovraccaricare la memoria stessa.
Diverso è il discorso su chip che prevedono l'uso di memoria RAM esterna come memoria estesa, tipo l'Atmega128 e l'Atmega1280/2560 dell'Arduino MEGA. Qui allora avere 64 kB di Ram può anche giustificare l'uso delle tecniche suddette. Ma su 2kB di Ram conviene? Non so.

leo, non ti seguo. sia che fai una lista, un array, una semplice variabile, o anche una NEW, dietro c'è sempre una malloc più o meno nascosta.

@clodiny: ho controllato, non conosco bene il c++ e effettivamente hai ragione. A quanto pare non hanno overloadato il costrutto new con il supporto di array. d'altronde anche l'operatore new è stato appena aggiunto. Sono sicuro che in giro per il forum trovi un pezzo di codice per aggiungere il new alle vecchie versioni di IDE, e forse pure che supporta gli array

lesto:
leo, non ti seguo. sia che fai una lista, un array, una semplice variabile, o anche una NEW, dietro c'è sempre una malloc più o meno nascosta.

Parlavamo di allocazione dinamica della memoria. Fare un array dinamico globale comporta un bel po' di salti pindarici, o mi sbaglio? Tu che sei esperto di C++ potrai spiegarlo meglio che di me, ma non penso che sia una cosa che possa portare benifici.
Un conto è allocare un array in una routine, l'array verrà creato e morirà lì ed avrà le sue celle. Ma un array dinamico a me pare molto più complesso da gestire: se durante la vita dello sketch, le sue dimensioni aumentano e diminuiscono di continuo, come fai a gestire la cosa senza spendere molte risorse?
Prendiamo il caso seguente:
byte a
a.add(12)
byte b=1
a nasce, ma non ha celle. Poi gli viene aggiunta una cella per contenere 12. Quindi nella memoria viene creato b. Mettiamo che a questo punto si chiami la routine pippo che crea una variabile locale c=2 e poi questa stessa routine aggiunga una cella all'array. Terminata la routine, c viene distrutto e resta il "buco" in memoria. Ora lo sketch principale aggiunge 2 celle ad a: 1 andrà ad occupare il buco lasciato da c e l'altra verrà aggiunta nella 1a locazione di memoria libera. Ecc... ecc...
Non è un sovraccarico di lavoro? Domando, eh... :sweat_smile:

questo è un esempio per fare venire fuori l’errore.
il mio intento è di capire se si possono creare array dinamici.

L’array dinamico si fa con le liste concatenate e con allocazione dinamica, il fatto è che sotto sotto gli opertatori new e delete chiamano malloc e free ed è vero che si può allocare qualsiasi tipo di dato con new anche se io new e delete li ho sempre usati
nella forma conosciuta Tipo *ptr_Tipo = new Tipo(). Però io non ho mai avuto necessità di un array di interi di dimensioni predefinite, per cui non so se è una limitazione dei metodi new e delete che comporta quell’errore.

Poi io ho sempre usato delete ptr_Tipo; gli operatori indice non li ho mai usati con delete anche perchè ne sconosco il significato.

ho dato un occhiata alla libreria delle QueueArray
così su due piedi mi sembra un template

QueueArray <char> queue;

programmazione ancora più spinta...

Si è template.

Ti do un consiglio guarda i sorgenti delle libreria di arduino io ricordo che c’è un file dove viene assegnato il compito a new e delete, il nome del file non lo ricordo ma mi sembra abbia un nome facilmente identificabile.

leo72:

lesto:
leo, non ti seguo. sia che fai una lista, un array, una semplice variabile, o anche una NEW, dietro c’è sempre una malloc più o meno nascosta.

Parlavamo di allocazione dinamica della memoria. Fare un array dinamico globale comporta un bel po’ di salti pindarici, o mi sbaglio? Tu che sei esperto di C++ potrai spiegarlo meglio che di me, ma non penso che sia una cosa che possa portare benifici.
Un conto è allocare un array in una routine, l’array verrà creato e morirà lì ed avrà le sue celle. Ma un array dinamico a me pare molto più complesso da gestire: se durante la vita dello sketch, le sue dimensioni aumentano e diminuiscono di continuo, come fai a gestire la cosa senza spendere molte risorse?
Prendiamo il caso seguente:
byte a
a.add(12)
byte b=1
a nasce, ma non ha celle. Poi gli viene aggiunta una cella per contenere 12. Quindi nella memoria viene creato b. Mettiamo che a questo punto si chiami la routine pippo che crea una variabile locale c=2 e poi questa stessa routine aggiunga una cella all’array. Terminata la routine, c viene distrutto e resta il “buco” in memoria. Ora lo sketch principale aggiunge 2 celle ad a: 1 andrà ad occupare il buco lasciato da c e l’altra verrà aggiunta nella 1a locazione di memoria libera. Ecc… ecc…
Non è un sovraccarico di lavoro? Domando, eh… :sweat_smile:

I mecannismi interni con cui opera il compilatore sono davvero difficili da seguire, in teoria il motivo per cui si evita di
allocare memoria con malloc e nella velocità di esecuzione ma anche l’occupazione di memoria che ne deriva, perchè prima o poi free dovra liberare memoria rendendola libera per altri malloc, se si è costretti a farlo e porta benefici si fa, ma tenendo a mente che non siamo su un pc con memoria infinita e se new o malloc non riesce ad allocare memoria il programma fallisce.

Comunque al di là della utilità o meno, ci saranno casi in cui conviene usare new e sarebbe utile sapere nel dettaglio come si comporta il compilatore perchè in effetti c’è poca documentazione in giro su avr-g++, ad esempio io neanche sapevo che i template funzionanvano, come pure se i namespace sono abilitati e se per C e possibile usare i namespace (introdotti di recente).

Ciao.

@leo, come dicevo prima NON sono esperto di C++, ma quì stiamo parlando di C “puro”, che poi possa essere fatto e/o “sporcato” con il C++ è una altro paio di maniche.

iniziamo a dire che ci sono 2 versioni differenti: le liste e gli array.

partiamo dagli array.
una array non è altro che un insieme di dati dello stesso tipo(quindi della stessa dimensione in byte) CONSECUTIVI nella ram.
in questo modo tu hai solo l’indirizzo del primo elemento; se vuoi prendere per esempio il 5°, allora farai
indirizzo_base + dimensione_dato * numero_elemento
e questo spiega perchè il C usa lo 0 come primo elemento!! :grin:
quando vuoi aggiungere un nuovo elemento, allochi uno spazio di ram abbastanza grande, copi i vecchi elementi, e poi aggiungi quello nuovo.
Un trucco molto usato è di creare a priori un array di 10/15 elementi, e incrementarlo di 5 elementi a volta, così da diminuire il peso della copia degli elementi.
Poi esiste anche la realloc che tenta di AGGIUNGERE un pezzo di ram all’array che già eseiste, però deve essere consecutivo e quindi se hai creato nuove variabili dopo l’array che sono ancora in vita è molto probabile che fallisca… quindi fai realloc, se fallisce malloc + copia

quindi un array non può avere “buchi” al suo interno.
Vantaggi: semplice da usare e gestire, lettura random
Svataggi: se l’array o i suoi elementi sono grandi, potrebbe non essere possibile avere tutta quella ram consecutiva…bel problema

a questo punto ci sono le liste.
sono fatte così (di base, poi ci sono mille varianti):
crei una struttura, con il dato che vuoi contenere e un puntatore alla struttura stessa.
poi crei 1 puntatore alla struttura, che sarà il primo elemento della lista, vale null se non ce ne sono.
ogni volta che crei un nuovo elemento della lista, crei una struttura, che sarà in un punto a caso della ram, e le leghi tra loro attraverso il puntatore contenuto nella struttura. quindi quando vorrai leggere la lista parti dal puntatore al primo elemento, leggi l’elemento che nella sua struttura possiede il puntatore al prossimo elemento etc…
Vantaggi: frammenta un array che magari non ci starebbe mai nella ram in modo sequenziale, in tante piccole strutture a caso nella ram. Utile quindi nei SO complessi che possono soffrire di frammentazione della ram
svataggi: l’esempio proposto permette un accesso SEQUENZIALE e solo in un senso. se devi contenere dati int stai raddoppiando la memoria necessaria (essendo un puntatore di dimensione int), se byte la stai triplicando, etc…
la struttura rimane sequenziale, a meno che al suo interno non abbia puntatori, e così sì che stai creando un bel pò di frammentazione in ram! :slight_smile:

lesto:
non conosco bene il c++ ...

leo72:
Tu che sei esperto di C++ ...

XD XD XD

MauroTec:
Ti do un consiglio guarda i sorgenti delle libreria di arduino io ricordo che c’è un file dove viene assegnato il compito a new e delete, il nome del file non lo ricordo ma mi sembra abbia un nome facilmente identificabile.

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

New.cpp

#include <new.h>

void * operator new(size_t size)
{
  return malloc(size);
}

void operator delete(void * ptr)
{
  free(ptr);
} 

int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
void __cxa_guard_abort (__guard *) {}; 
void __cxa_pure_virtual(void) {};

@lesto:
non volevo prenderti in giro, ma in un altro thread avevi affermato che se si parlava di C++ tu eri ferrato perché lo avevi studiato a scuola. :wink: Ora, siccome io il C++ non lo conosc se non quel poco che ho imparato qui con voi, io cerco con la logica di sopperire alle mie lacune.

Tu mi stai quindi dicendo che quando ad un array cerco di aggiungere un elemento, il compilatore prende e copia tutto l'array da un'altra parte se non può aggiungere l'elemento nello spazio occupato prima dall'array. Vedi che allora è come dico io, che alla fine non conviene gestire la memoria così?
Se tu avessi un array di 100 elementi, poi aggiungi 1 variabile a caso, dopodiché vuoi aggiungere 1 elemento all'array, questo non ci starebbe e tutto l'array verrebbe copiato dopo la variabile che rompe le scatole nel mezzo. In questo modo perdo 100 byte di memoria in un colpo. Se poi tale memoria non la riadopero per altre cose, l'aggiunta di 1 solo elemento all'array è divenuta un'operazione altamente sconventiente.