Как я могу выполнить предосновную инициализацию в C/C++ с avr-gcc?

После долгих размышлений было решено исправить формат утилиты импорта. Экранирование строки было правильным (как отметили пользователи), но файл формата, используемый утилитой импорта, был некорректным и приводил к прерыванию импорта.

Спасибо всем и особая благодарность @dbt (голосование вверх)

9
задан Matthew Murdoch 4 June 2009 в 11:51
поделиться

8 ответов

Вы можете использовать GCC конструктор атрибут , чтобы гарантировать, что он вызывается перед main () :

void Init(void) __attribute__((constructor));
void Init(void) { /* code */ }  // This will always run before main()
13
ответ дан 4 December 2019 в 08:16
поделиться

Вот несколько злой метод достижения этого:

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

Добавьте следующее к флагам компоновщика: - обернуть main

например.

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

Компоновщик заменит все вызовы main с вызовами __ wrap_main , см. справочную страницу ld на - wrap

3
ответ дан 4 December 2019 в 08:16
поделиться

Вы можете немного сократить приведенное выше, указав возвращаемый тип "инициализировать" и используя его для инициализации глобальной переменной:

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

Однако вы должны быть осторожны с этим, стандарт не гарантирует, что вышеупомянутая инициализация (или инициализация вашего объекта инициализации) произойдет до запуска main (3.6.2 / 3):

Это реализация -определено, выполняется ли динамическая инициализация (8.5, 9.4, 12.1, 12.6. 1) объекта области видимости пространства имен выполняется перед первым оператором main.

Единственное, что гарантируется, - это то, что инициализация произойдет до того, как когда-либо будет использоваться 'dummy'.

Более навязчивый вариант (если это возможно) может быть использование "-D main = avr_main" в вашем make-файле. Затем вы можете добавить свой собственный main следующим образом:

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

По крайней мере, здесь вам гарантировано, что инициализация произойдет, когда вы ожидаете.

4
ответ дан 4 December 2019 в 08:16
поделиться

Простое и понятное решение. Что вы можете дополнительно сделать, так это поместить свой код в анонимное пространство имен. Я не вижу необходимости делать это лучше, чем это :)

2
ответ дан 4 December 2019 в 08:16
поделиться

Использовать статические члены классов. Они инициализируются перед входом в main. Недостатком является то, что вы не можете контролировать порядок инициализации статических членов класса.

Вот ваш преобразованный пример:

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;
0
ответ дан 4 December 2019 в 08:16
поделиться

Если вы используете среду Arduino, есть ли причина, по которой вы не можете поместить ее в метод установки ?

Конечно, это после Arduino -специфическая настройка оборудования, поэтому, если у вас есть такие низкоуровневые вещи, которые действительно должны идти до main , тогда вам понадобится магия конструктора.

UPDATE:

Хорошо, если это необходимо быть сделано перед основным Я думаю, что единственный способ - использовать конструктор, как вы уже делаете.

Вы всегда можете сделать из него макрос препроцессора:

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

Теперь это должно работать:

RUN_EARLY(initialize())

Но на самом деле он не делает вещи короче, просто перемещая подробный код.

2
ответ дан 4 December 2019 в 08:16
поделиться

Конечно, вы помещаете это в один из ваших файлов заголовков, скажем, preinit.h:

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

, а затем в один из ваших единиц компиляции, помещаете:

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

Я знаю, что это кладж, но я не знаю какого-либо переносимого способа выполнить предварительную инициализацию без использования конструктора класса, выполняемого в области видимости файла.

Вы также должны быть осторожны и включать больше чем одна из этих функций инициализации, поскольку я не верю, что С ++ диктует порядок - он может быть случайным.

Я не уверен в этом «эскизе», о котором вы говорите, но возможно ли преобразовать основную единицу компиляции перед передачей в компилятор скрипта, например:

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

Вы можете увидеть, как это повлияет на вашу программу, потому что:

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

генерирует следующее с добавленным вызовом initialize () :

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

Возможно, вы не сможете выполнить постобработку сгенерированного файла, и в этом случае вам следует проигнорировать последний вариант, но это то, что я буду искать в первую очередь.

0
ответ дан 4 December 2019 в 08:16
поделиться

Вы можете использовать разделы ".init *" для добавления кода C, который будет запускаться перед main () (и даже средой выполнения C). Эти разделы связаны с исполняемым файлом в конце и вызываются в определенное время во время инициализации программы. Вы можете получить список здесь:

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

.init1, например, слабо привязан к __init (), поэтому, если вы определите __init (), он будет связан и вызван первым делом. Однако стек не был настроен, поэтому вы должны быть осторожны в своих действиях (используйте только переменную register8_t, не вызывайте никаких функций).

2
ответ дан 4 December 2019 в 08:16
поделиться