Pregunta

Para garantizar que algún código de inicialización se ejecute antes main (usando Arduino/avr-gcc) Tengo un código como el siguiente:

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

Init init;

Idealmente me gustaría poder simplemente escribir:

initialize();

pero esto no se compila...

¿Existe una forma menos detallada de lograr el mismo efecto?

Nota: el código es parte de un boceto de Arduino por lo que main La función se genera automáticamente y no se puede modificar (por ejemplo, para llamar initialize antes que cualquier otro código).

Actualizar: Lo ideal sería que la inicialización se realizara en el setup función, pero en este caso hay otro código que depende de ella y que ocurre antes main.

¿Fue útil?

Solución

Puede utilizar atributo constructor para asegurar que se llama antes de main():

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

Otros consejos

Usted puede hacer lo anterior muy ligeramente más corta, dando "inicializar" un tipo de retorno, y utilizarlo para inicializar una variable global:

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

Sin embargo, es necesario tener cuidado con esto, la norma no garantiza que la inicialización por encima (o el de su objeto init) se lleva a cabo antes de ejecutar principal (3.6.2 / 3):

  

Se define-aplicación si o no la inicialización dinámica (8.5, 9.4, 12.1, 12.6.1) de un objeto de alcance espacio de nombres se realiza antes de la primera declaración de principal.

Lo único que está garantizado es que la inicialización se llevará a cabo antes del 'maniquí' es utilizado siempre.

Una opción más intrusiva (si es posible) podría ser el uso de "-D principal = avr_main" en su makefile. A continuación, puede añadir su propio principal de la siguiente manera:

// 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);
}

Al menos aquí tiene la garantía de que la inicialización se llevará a cabo cuando se espera.

Esto es un método algo mal de lograr esto:

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

Agregue lo siguiente a las banderas de engarce: --wrap main

por ejemplo.

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

El enlazador reemplazará todas las llamadas a main con llamadas a __wrap_main, consulte la LD página del manual en --wrap

Su solución en simple y limpio. Lo que puede hacer, además, es poner su código en espacio de nombres en el anonimato. No veo ninguna necesidad de hacerlo mejor que eso:)

Si está utilizando el entorno de Arduino, ¿hay alguna razón no se puede colocar en los href="http://arduino.cc/en/Reference/Setup" método?

Por supuesto, esto es después de la instalación del hardware Arduino-específica, por lo que si usted tiene la misma sustancia de bajo nivel que realmente tiene que recorrer antes de main, entonces usted necesita un poco de magia constructor.

ACTUALIZACIÓN:

Ok, si se tiene que hacer antes de que el principal Creo que la única manera es utilizar un constructor, como ya lo hacen.

Siempre se puede hacer una macro preprocesador de ella:

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

Ahora bien, esto debería funcionar:

RUN_EARLY(initialize())

Pero no es realmente hacer las cosas más corta, sólo mover el código detallado alrededor.

Puede utilizar el ".init *" secciones para agregar el código C para ejecutarse antes de main () (e incluso el tiempo de ejecución C). Estas secciones están unidas en el ejecutable al final y llamados a una hora específica durante la inicialización del programa. Puede obtener la lista aquí:

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

.init1 por ejemplo, está débilmente unida a __init (), por lo que si se define __init (), que se vinculará y llamó a primera hora. Sin embargo, la pila no se ha configurado, por lo que tiene que tener cuidado en lo que haces (sólo utiliza la variable register8_t, no llame a cualquiera de las funciones).

Utilice los miembros estáticos de clases. Se inicializan antes de entrar a la principal. La desventaja es que no se puede controlar el orden de la inicialización de los miembros de la clase estática.

A continuación, se transformó el ejemplo:

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;

Por supuesto, se pone esto en una de sus sus archivos de cabecera, dice preinit.h:

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

y, a continuación, en un de sus unidades de compilación, poner:

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

Sé que es una chapuza, pero no estoy al tanto de cualquier manera portátil para hacer la inicialización pre-principal sin necesidad de utilizar un constructor de la clase ejecutado en el ámbito de archivo.

También debe tener cuidado de incluir más de una de estas funciones de inicialización ya no creo C ++ dicta la orden -. Podría ser al azar

No estoy seguro de esto "boceto" de la que usted habla, pero ¿sería posible transformar la unidad principal de la compilación con un guión antes de tener que pasar al compilador, algo como:

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

Se puede ver cómo esto afectaría a su programa, ya que:

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

genera el siguiente con la llamada initialize() Añadido:

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

Puede ser que no se puede post-proceso, el archivo generado en cuyo caso se debe pasar por alto que la última opción, pero eso es lo que estaría buscando en un primer momento.

Así es como realizo la codificación previa a la principal.Hay varias secciones de inicio ejecutadas antes de la principal, se refiere a http://www.nongnu.org/avr-libc/user-manual/mem_sections.html secciones iniciales.

De todos modos, esto solo funciona en la optimización -O0 por alguna razón.Todavía trato de averiguar qué opción "optimizó" mi código ensamblador previo al principal.

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

Actualización, resulta que afirmé que esta función no se utiliza, lo que llevó a optimizar la rutina.Tenía la intención de eliminar la función de advertencia no utilizada.En su lugar, se fija en el atributo usado usado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top