Question

Afin d'assurer que du code d'initialisation exécute avant main (en utilisant Arduino / avr-gcc) J'ai le code tel que le suivant:

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

Init init;

Idéalement, je voudrais pouvoir écrire simplement:

initialize();

mais cela ne compile pas ...

Y at-il un moyen moins bavard pour obtenir le même effet?

Note:. le code fait partie d'une esquisse Arduino si la fonction de main est généré automatiquement et ne peut pas être modifiée (par exemple pour appeler initialize avant tout autre code)

Mise à jour:. idéalement l'initialisation serait effectuée dans la fonction setup, mais dans ce cas, il est tout autre code en fonction de ce qui se produit avant main

Était-ce utile?

La solution

Vous pouvez utiliser le constructor attribut pour veiller à ce qu'il est appelé avant main():

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

Autres conseils

Vous pouvez faire ce qui précède très légèrement plus court en donnant « initialiser » un type de retour, et à l'aide que pour initialiser une variable globale:

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

Cependant, vous devez être prudent avec cela, la norme ne garantit pas que l'initialisation ci-dessus (ou celui de votre objet init) a lieu avant principal est exécuté (3.6.2 / 3):

  

Il est défini par l'implémentation si l'initialisation dynamique ou non (8.5, 9.4, 12.1, 12.6.1) d'un objet de champ d'espace de noms est effectué avant la première déclaration de la principale.

La seule chose qui est garanti est que l'initialisation aura lieu avant que « factice » est déjà utilisé.

Une option plus intrusive (si possible) pourrait être d'utiliser "-D principal = avr_main" dans votre makefile. Vous pouvez ensuite ajouter votre propre principal comme suit:

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

Au moins ici, vous êtes assuré que l'initialisation aura lieu lorsque vous vous attendez.

Voici une méthode un peu mal d'y parvenir:

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

Ajoutez ce qui suit aux drapeaux de l'éditeur de liens: --wrap main

par exemple.

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

L'éditeur de liens remplacera tous les appels à main avec des appels à __wrap_main, consultez le ld page man sur --wrap

Votre solution simple et propre. Ce que vous pouvez en outre faire est de mettre votre code dans l'espace de noms anonyme. Je ne vois pas la nécessité de faire mieux que cela:)

Si vous utilisez l'environnement Arduino, est-il une raison quelconque vous ne pouvez pas le placer dans les méthode ?

Bien sûr, cela est après la configuration matérielle spécifique à l'Arduino, donc si vous avez une telle substance à faible niveau qu'il a vraiment aller avant main, alors vous avez besoin de la magie du constructeur.

Mise à jour:

Ok, si elle doit être fait avant la principale, je pense que la seule façon est d'utiliser un constructeur comme vous le faites déjà.

Vous pouvez toujours faire une macro préprocesseur de celui-ci:

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

Maintenant, cela devrait fonctionner:

RUN_EARLY(initialize())

Mais il est pas vraiment faire des choses plus courtes, juste déplacer le code bavard autour.

Vous pouvez utiliser le ".init *" sections d'ajouter du code C à exécuter avant main () (et même le moteur d'exécution C). Ces sections sont liées à l'exécutable à la fin et appelés à des moments précis lors de l'initialisation du programme. Vous pouvez obtenir la liste ici:

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

.init1 par exemple, est faiblement liée à __init (), donc si vous définissez __init (), il sera lié et a appelé la première chose. Cependant, la pile n'a pas été configuré, vous devez faire attention à ce que vous ne (utilisez seule variable register8_t, pas appeler toutes les fonctions).

Utilisez les membres statiques des classes. Ils sont initialisés avant d'entrer au principal. L'inconvénient est que vous ne pouvez pas contrôler l'ordre de l'initialisation des membres statiques de classe.

Voici votre exemple transformé:

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;

Bien sûr, vous mettez cela dans l'un de vos fichiers d'en-tête, dites preinit.h:

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

et puis, dans un de vos unités de compilation, mettez:

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

Je sais que c'est une bidouille mais je ne suis pas au courant de any de manière portable faire l'initialisation avant principal sans utiliser un constructeur de classe exécuté à la portée du fichier.

Vous devez aussi être prudent d'inclure plus d'une de ces fonctions d'initialisation puisque je ne crois pas que C ++ dicte l'ordre -. Il pourrait être aléatoire

Je ne suis pas sûr de ce « croquis » dont vous parlez, mais serait-il possible de transformer l'unité principale de compilation avec un script avant de l'avoir passé au compilateur, quelque chose comme:

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

Vous pouvez voir comment cela aurait une incidence sur votre programme parce que:

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

génère le texte suivant à l'appel initialize() ajouté:

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

Il se peut que vous ne pouvez pas post-traitement du fichier généré dans ce cas, vous devez ignorer cette dernière option, mais c'est ce que je regarderais d'abord.

Il est comment j'effectuer un codage pré-principal. Il y a sever sections init exécute avant principal, se réfère à http: // www. sections nongnu.org/avr-libc/user-manual/mem_sections.html initN.

Quoi qu'il en soit, cela ne fonctionne que sur l'optimisation -O0 pour une raison quelconque. J'essaie toujours de savoir quelle option « optimisé » mon code de pré-assemblage principal de suite.

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

Mise à jour, il se trouve que je prétendais cette fonction est utilisé, ce qui conduit à optimiser loin la routine. Je l'intention de tuer la fonction d'avertissement utilisé. Il est fixé à utiliser l'attribut utilisé à la place.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top