Frage

Um sicherzustellen, dass einige Initialisierungscode ausgeführt wird, bevor main (mit Arduino / avr-gcc) I-Code haben wie folgt:

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

Init init;

Im Idealfall würde Ich mag zu können, einfach schreiben:

initialize();

aber nicht kompilieren ...

Gibt es eine weniger ausführliche Art und Weise die gleiche Wirkung zu erzielen?

. Hinweis: der Code Teil einer Arduino Skizze ist, so dass die main Funktion wird automatisch generiert und kann nicht verändert werden (zum Beispiel initialize nennt vor jedem anderen Code)

Update:. im Idealfall würde die Initialisierung in der setup Funktion ausgeführt werden, aber in diesem Fall gibt es einen anderen Code auf es abhängig, die vor main auftritt

War es hilfreich?

Lösung

Sie können die GCC constructor Attribut um sicherzustellen, dass es vor main() aufgerufen wird:

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

Andere Tipps

Sie können die oben machen sehr wenig kürzer durch „initialisieren“ einen Rückgabetyp geben, und die Verwendung dieser eine globale Variable zu initialisieren:

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

Allerdings müssen Sie damit vorsichtig sein, schreibt die Norm nicht garantieren, dass die obige Initialisierung (oder die für Ihr init-Objekt) stattfindet, bevor Haupt ausgeführt wird (3.6.2 / 3):

  

Es ist die Implementierung definiert, ob die dynamische Initialisierung (8.5, 9.4, 12.1, 12.6.1) ein Objekts von Namespacebereich vor der ersten Anweisung des Hauptdurchgeführt wird.

Das einzige, was garantiert ist, dass die Initialisierung statt, bevor ‚Dummy‘ nehmen wird immer verwendet.

Eine intrusive Option (wenn es möglich ist) könnte "-D main = avr_main" in Ihrer Make-Datei zu verwenden. Sie könnten dann Ihre eigene Haupt hinzufügen wie folgt:

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

Wenigstens hier sind Sie garantiert, dass die Initialisierung stattfinden wird, wenn Sie erwarten.

Hier ist eine etwas böse Methode, dies zu erreichen:

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

Fügen Sie folgende an den Linker-Flags: --wrap main

zB.

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

Der Linker wird alle Anrufe ersetzen Anrufe main __wrap_main finden Sie in der ld Mann auf --wrap

Ihre Lösung in einfach und sauber. Was können Sie zusätzlich zu tun ist, Ihren Code in anonymen Namensraum zu setzen. Ich sehe keine Notwendigkeit, es besser zu machen als das:)

Wenn Sie die Arduino-Umgebung verwenden, gibt es keinen Grund Sie nicht in den Setup rel="nofollow Verfahren ?

Natürlich ist dies nach dem Arduino-spezifische Hardware-Setup, so dass, wenn Sie eine solche Low-Level-Zeug haben, dass es wirklich vor main gehen muss, dann müssen Sie einige Konstruktor Magie.

UPDATE:

Ok, wenn es vor dem Haupt getan werden muss, glaube ich, der einzige Weg, einen Konstruktor zu verwenden ist, wie Sie bereits tun.

Sie können immer einen Präprozessormakro davon machen:

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

Nun sollte diese Arbeit:

RUN_EARLY(initialize())

Aber es ist nicht wirklich die Dinge kürzer, gleich um den ausführlichen Code bewegen.

Sie können die „.init *“ Abschnitte C-Code hinzufügen, bevor main () (und auch die C-Laufzeit) ausgeführt werden. Diese Abschnitte werden in die ausführbaren Datei am Ende verknüpft und zu einem bestimmten Zeit während des Programms Initialisierung aufgerufen. Sie können die Liste erhalten Sie hier:

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

.init1 zum Beispiel schwach an __init () gebunden, wenn Sie also __init definieren (), wird es verknüpft und als erstes aufgerufen werden. Allerdings hat der Stapel nicht eingerichtet worden, so dass Sie in vorsichtig sein, was Sie tun (nur register8_t Variable verwenden, keine Funktionen aufrufen).

Verwenden Sie statische Elemente von Klassen. Sie werden vor dem Eintritt zur Haupt initialisiert. Der Nachteil ist, dass Sie nicht die Reihenfolge der Initialisierung der statischen Klassenelemente steuern können.

Hier ist Ihr Beispiel transformiert:

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;

Sicher, Sie setzen diese in einem Ihrer Ihre Header-Dateien, sagen preinit.h:

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

und dann, in ein Ihre Übersetzungseinheiten setzen:

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

Ich weiß, dass eine Flickschusterei, aber ich bin mir nicht bewusst jeder tragbare Art und Weise. Eine Klasse Konstruktor ohne Verwendung in Dateigültigkeitsbereich ausgeführt Pre-Haupt-Initialisierung zu tun

Sie sollten auch vorsichtig sein, mehr als eine dieser Initialisierungsfunktionen von einschließlich da ich nicht glaube, C ++ die Reihenfolge bestimmt, -. Es zufällig sein könnte

Ich bin nicht sicher, ob dieser „Skizze“, von dem Sie sprechen, aber es wäre die Hauptübersetzungseinheit mit einem Skript zu verwandeln möglich sein, bevor er sie an den Compiler übergeben, so etwas wie:

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

Sie können sehen, wie dies Ihr Programm auswirken würde, weil:

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

generiert die folgende mit dem initialize() Aufruf hinzugefügt:

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

Es kann sein, dass Sie nicht nachbearbeiten die erzeugte Datei in dem Fall, dass Sie diese letzte Option ignorieren sollen, aber das ist, was würde ich zuerst suchen.

Es ist, wie ich vorgeHaupt Codierung durchführen. Es gibt Sever init Abschnitte vor dem Haupt ausgeführt wird, bezieht sich auf http: // www. nongnu.org/avr-libc/user-manual/mem_sections.html Initn Abschnitte.

Wie auch immer, dies funktioniert nur auf -O0 Optimierung aus irgendeinem Grunde. Ich versuche immer noch, um herauszufinden, welche Option „optimiert“ mein Pre-Haupt-Assembler-Code entfernt.

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, es stellt sich heraus, dass ich behauptet, diese Funktion nicht verwendet wird, führt die Routine weg zu optimieren. Ich beabsichtigte Funktion nicht verwendete Warnung zu töten. Es wird festgelegt, anstatt gebrauchtes Attribut verwendet wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top