После долгих размышлений было решено исправить формат утилиты импорта. Экранирование строки было правильным (как отметили пользователи), но файл формата, используемый утилитой импорта, был некорректным и приводил к прерыванию импорта.
Спасибо всем и особая благодарность @dbt (голосование вверх)
Вы можете использовать GCC конструктор
атрибут , чтобы гарантировать, что он вызывается перед main ()
:
void Init(void) __attribute__((constructor));
void Init(void) { /* code */ } // This will always run before main()
Вот несколько злой метод достижения этого:
#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
Вы можете немного сократить приведенное выше, указав возвращаемый тип "инициализировать" и используя его для инициализации глобальной переменной:
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);
}
По крайней мере, здесь вам гарантировано, что инициализация произойдет, когда вы ожидаете.
Простое и понятное решение. Что вы можете дополнительно сделать, так это поместить свой код в анонимное пространство имен. Я не вижу необходимости делать это лучше, чем это :)
Использовать статические члены классов. Они инициализируются перед входом в 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;
Если вы используете среду Arduino, есть ли причина, по которой вы не можете поместить ее в метод установки ?
Конечно, это после Arduino -специфическая настройка оборудования, поэтому, если у вас есть такие низкоуровневые вещи, которые действительно должны идти до main
, тогда вам понадобится магия конструктора.
UPDATE:
Хорошо, если это необходимо быть сделано перед основным Я думаю, что единственный способ - использовать конструктор, как вы уже делаете.
Вы всегда можете сделать из него макрос препроцессора:
#define RUN_EARLY(code) \
namespace { \
class Init { \
Init() { code; } \
}; \
Init init; \
}
Теперь это должно работать:
RUN_EARLY(initialize())
Но на самом деле он не делает вещи короче, просто перемещая подробный код.
Конечно, вы помещаете это в один из ваших файлов заголовков, скажем, 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;
}
Возможно, вы не сможете выполнить постобработку сгенерированного файла, и в этом случае вам следует проигнорировать последний вариант, но это то, что я буду искать в первую очередь.
Вы можете использовать разделы ".init *" для добавления кода C, который будет запускаться перед main () (и даже средой выполнения C). Эти разделы связаны с исполняемым файлом в конце и вызываются в определенное время во время инициализации программы. Вы можете получить список здесь:
http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
.init1, например, слабо привязан к __init (), поэтому, если вы определите __init (), он будет связан и вызван первым делом. Однако стек не был настроен, поэтому вы должны быть осторожны в своих действиях (используйте только переменную register8_t, не вызывайте никаких функций).