programas - manual completo de c++ pdf
¿Cómo puedo realizar la inicialización pre-main en C/C++ con avr-gcc? (9)
Para asegurarme de que algún código de inicialización se ejecute antes que el main
(usando Arduino / avr-gcc), tengo un código como el siguiente:
class Init {
public:
Init() { initialize(); }
};
Init init;
Idealmente, me gustaría poder escribir simplemente:
initialize();
pero esto no compila ...
¿Hay una forma menos verbosa de lograr el mismo efecto?
Nota: el código es parte de un boceto de Arduino, por lo que la función main
se genera automáticamente y no se puede modificar (por ejemplo, para initialize
llamada antes que cualquier otro código).
Actualización: idealmente, la inicialización se realizaría en la función de setup
, pero en este caso hay otro código que depende de él y que ocurre antes de la función main
.
Aquí hay un método un tanto malvado para 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 los indicadores del vinculador: --wrap main
p.ej.
gcc -Xlinker --wrap -Xlinker main a.c
El enlazador reemplazará todas las llamadas a main
con llamadas a __wrap_main
, consulte la página man de ld en - --wrap
Así es como realizo la codificación pre-main. Hay secciones init de inicio ejecutadas antes de main, se refiere a http://www.nongnu.org/avr-libc/user-manual/mem_sections.html secciones initN.
De todos modos, esto solo funciona con la optimización -O0 por alguna razón. Todavía trato de averiguar qué opción "optimizó" mi código de ensamblaje pre-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 dije que esta función no se usa, lo que lleva a optimizar la rutina. Tenía la intención de matar la función de advertencia no utilizada. Se fija al atributo usado usado en su lugar.
Claro, pones esto en uno de tus archivos de encabezado, di preinit.h:
class Init { public: Init() { initialize(); } }; Init init;
y luego, en una de tus unidades de compilación, pon:
void initialize(void) {
// weave your magic here.
}
#include "preinit.h"
Sé que es un error, pero no conozco ninguna forma portátil de inicialización previa sin utilizar un constructor de clase ejecutado en el alcance del archivo.
También debe tener cuidado de incluir más de una de estas funciones de inicialización ya que no creo que C ++ dicte el orden, podría ser aleatorio.
No estoy seguro de este "boceto" del que hablas, pero sería posible transformar la unidad de compilación principal con un script antes de pasarlo al compilador, algo así como:
awk ''{print;if (substr($0,0,11) == "int main (") {print "initialize();"};}''
Puedes ver cómo esto afectaría tu programa porque:
echo ''#include <stdio.h>
int main (void) {
int x = 1;
return 0;
}'' | awk ''{
print;
if (substr($0,0,11) == "int main (") {
print " initialize();"
}
}''
genera lo siguiente con la llamada initialize()
agregada:
#include <stdio.h>
int main (void) {
initialize();
int x = 1;
return 0;
}
Puede ser que no puedas postprocesar el archivo generado, en cuyo caso deberías ignorar esa opción final, pero eso es lo que estaría mirando primero.
Puede hacer que lo anterior sea muy breve al dar "inicializar" un tipo de devolución y usarlo para inicializar una variable global:
int initialize();
int dummy = initialize();
Sin embargo, debe tener cuidado con esto, el estándar no garantiza que la inicialización anterior (o la de su objeto init) tenga lugar antes de que se ejecute main (3.6.2 / 3):
Está definido por la implementación ya sea que la inicialización dinámica (8.5, 9.4, 12.1, 12.6.1) de un objeto de ámbito de espacio de nombres se realice o no antes de la primera declaración de main.
Lo único que está garantizado es que la inicialización tendrá lugar antes de que se use ''dummy''.
Una opción más intrusiva (si es posible) podría ser usar "-D main = avr_main" en su archivo MAKE. A continuación, puede agregar 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í tienes garantizado que la inicialización tendrá lugar cuando lo esperes.
Puede usar el atributo de constructor
de GCC para asegurarse de que se llame antes de main()
:
void Init(void) __attribute__((constructor));
void Init(void) { /* code */ } // This will always run before main()
Puede usar las secciones ".init *" para agregar código C para ejecutar antes de main () (e incluso el tiempo de ejecución de C). Estas secciones se vinculan al ejecutable al final y se llaman en un momento específico 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 vinculado a __init (), por lo que si defines __init (), se vinculará y se llamará a primera vista. Sin embargo, la pila no se ha configurado, por lo que debe tener cuidado con lo que hace (solo use la variable register8_t, no llame a ninguna función).
Si está utilizando el entorno Arduino, ¿hay alguna razón por la que no pueda ubicarlo en el método de configuración ?
Por supuesto, esto es después de la configuración de hardware específica de Arduino, así que si tienes cosas de bajo nivel que realmente tienen que pasar antes que las main
, entonces necesitas algo de magia de constructor.
ACTUALIZAR:
Ok, si tiene que hacerse antes de la principal, creo que la única forma es usar un constructor como ya lo hace.
Siempre puede hacer una macro de preprocesador de ella:
#define RUN_EARLY(code) /
namespace { /
class Init { /
Init() { code; } /
}; /
Init init; /
}
Ahora esto debería funcionar:
RUN_EARLY(initialize())
Pero en realidad no hace las cosas más cortas, solo mueve el código detallado.
Su solución es simple y limpia. Lo que también puede hacer es colocar su código en el espacio de nombres anónimo. No veo ninguna necesidad de hacerlo mejor que eso :)
Use miembros estáticos de clases. Se inicializan antes de ingresar a main. La desventaja es que no puede controlar el orden de inicialización de los miembros de la clase estática.
Aquí está tu ejemplo transformado:
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;