Domanda

Al fine di garantire che un certo codice di inizializzazione viene eseguito prima main (utilizzando Arduino / AVR-gcc) Ho codice come il seguente:

class Init {
public:
    Init() { initialize(); }
};

Init init;

Idealmente mi piacerebbe essere in grado di scrivere semplicemente:

initialize();

, ma questo non compila ...

C'è un modo meno dettagliato per ottenere lo stesso effetto?

Nota. il codice è parte di uno schizzo Arduino così la funzione main viene generato automaticamente e non può essere modificato (ad esempio per chiamare initialize prima di qualsiasi altro codice)

Aggiornamento:. idealmente l'inizializzazione sarebbe eseguita nella funzione setup, ma in questo caso non v'è altro codice a seconda di ciò che si verifica prima main

È stato utile?

Soluzione

È possibile utilizzare attributo constructor per garantire che venga chiamato prima main():

void Init(void) __attribute__((constructor));
void Init(void) { /* code */ }  // This will always run before main()

Altri suggerimenti

È possibile effettuare quanto sopra molto leggermente più corta, dando "inizializzare" un tipo di ritorno, e l'utilizzo che per inizializzare una variabile globale:

int initialize();
int dummy = initialize();

Tuttavia, è necessario stare attenti a questo, lo standard non garantisce che l'inizializzazione sopra (o quello per l'oggetto init) si svolge prima principale viene eseguito (3.6.2 / 3):

  

Si attuazione definita o meno l'inizializzazione dinamica (8.5, 9.4, 12.1, 12.6.1) di un oggetto di portata namespace viene effettuata prima della prima istruzione del principale.

L'unica cosa che è garantito è che l'inizializzazione avverrà prima di 'manichino' viene mai utilizzato.

Un'opzione più invadente (se è possibile) potrebbe essere quella di usare "-D principale = avr_main" nel makefile. Si potrebbe quindi aggiungere la tua principale come segue:

// Add a declaration for the main declared by the avr compiler.
int avr_main (int argc, const char * argv[]);  // Needs to match exactly

#undef main
int main (int argc, const char * argv[])
{
  initialize ();
  return avr_main (argc, argv);
}

Almeno qui il gioco è garantito che l'inizializzazione avverrà quando ci si aspetta.

Ecco un metodo un po 'male per raggiungere tale obiettivo:

#include <stdio.h>

static int bar = 0;

int __real_main(int argc, char **argv);

int __wrap_main(int argc, char **argv)
{
    bar = 1;
    return __real_main(argc, argv);
}

int main(int argc, char **argv)
{
    printf("bar %d\n",bar);
    return 0;
}

Aggiungere il seguente alle bandiere linker: --wrap main

ad es.

gcc -Xlinker --wrap -Xlinker main a.c

Il linker sostituirà tutte le chiamate al main con le chiamate a __wrap_main, vedere la ld pagina man su --wrap

La vostra soluzione in modo semplice e pulito. Che cosa si può inoltre fare è di mettere il codice in namespace anonimo. Non vedo alcuna necessità di fare meglio di questo:)

Se si utilizza l'ambiente Arduino, c'è qualche ragione per cui non è possibile inserire nelle href="http://arduino.cc/en/Reference/Setup" metodo ?

Naturalmente, questo è dopo la configurazione hardware Arduino-specifica, per cui se si dispone di tale roba di basso livello che ha davvero da fare prima main, allora avete bisogno di qualche magia costruttore.

UPDATE:

Ok, se deve essere fatto prima che il principale Credo che l'unico modo è quello di utilizzare un costruttore come già fate.

Si può sempre fare una macro di preprocessore di esso:

#define RUN_EARLY(code) \
namespace { \
    class Init { \
        Init() { code; } \
    }; \
    Init init; \
}

Ora, questo dovrebbe funzionare:

RUN_EARLY(initialize())

Ma non è davvero facendo le cose più breve, semplicemente spostando il codice verbose intorno.

È possibile utilizzare il ".init *" sezioni per aggiungere il codice C per essere eseguito prima di main () (e anche il runtime C). Queste sezioni sono collegate nell'eseguibile alla fine e richiamati a tempo specifico durante l'inizializzazione del programma. È possibile ottenere la lista qui:

http://www.nongnu.org/avr-libc /user-manual/mem_sections.html

.init1 ad esempio si lega debolmente alle __init (), quindi se si definisce __init (), che sarà collegato e chiamò prima cosa. Tuttavia, lo stack non è stata impostata, quindi bisogna stare attenti a quello che fate (utilizzare solo variabili register8_t, non chiamare qualsiasi funzione).

Utilizzare i membri statici di classi. Essi vengono inizializzate prima di entrare principale. Lo svantaggio è che non si può controllare l'ordine di inizializzazione dei membri della classe statici.

Ecco il tuo esempio trasforma:

class Init {
private:
    // Made the constructor private, so to avoid calling it in other situation
    // than for the initialization of the static member.
    Init() { initialize(); }

private:
    static Init INIT;
};


Init Init::INIT;

Certo, si mette questo in uno dei tuoi file di intestazione, dici preinit.h:

class Init { public: Init() { initialize(); } }; Init init;

e poi, in una delle vostre unità di compilazione, mettere:

void initialize(void) {
    // weave your magic here.
}
#include "preinit.h"

Lo so che è un ripiego, ma io non sono a conoscenza di qualsiasi modo portabile di fare l'inizio di pre-main senza utilizzare un costruttore della classe eseguito nell'ambito di file.

Si dovrebbe anche fare attenzione di includere più di una di queste funzioni di inizializzazione in quanto non credo che C ++ determina l'ordine -. Potrebbe essere casuale

Non sono sicuro di questo "sketch" di cui parli, ma sarebbe possibile trasformare l'unità di compilazione principale con uno script prima di averlo passato al compilatore, qualcosa come:

awk '{print;if (substr($0,0,11) == "int main (") {print "initialize();"};}'

Si può vedere come questo potrebbe influenzare il vostro programma perché:

echo '#include <stdio.h>
int main (void) {
    int x = 1;
    return 0;
}' | awk '{
    print;
    if (substr($0,0,11) == "int main (") {
        print "    initialize();"
    }
}'

genera il seguente con la chiamata initialize() aggiunto:

#include <stdio.h>
int main (void) {
    initialize();
    int x = 1;
    return 0;
}

E 'possibile che non si può post-processo il file generato, nel qual caso si deve ignorare che l'opzione finale, ma è quello che mi sarei cercato in un primo momento.

Non è come effettuo codifica pre-principale. Ci sono sezioni sever init eseguiti prima principale, si riferisce a http: // www. nongnu.org/avr-libc/user-manual/mem_sections.html initN sezioni.

In ogni caso, questo funziona solo su -O0 ottimizzazione per qualche motivo. Cerco ancora di scoprire quale opzione "ottimizzato" il mio codice assembly pre-principale via.

static void
__attribute__ ((naked))
__attribute__ ((section (".init8")))    /* run this right before main */
__attribute__ ((unused))    /* Kill the unused function warning */
stack_init(void) {assembly stuff}

Update, si scopre ho sostenuto questa funzione è inutilizzata, che porta a ottimizzare la routine di distanza. Mi aveva lo scopo di uccidere i warning non utilizzata la funzione. Si fissa utilizzata attributo usato preferibilmente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top