Pergunta

A fim de garantir que algumas corridas de código de inicialização antes main (usando Arduino / avr-gcc) Eu tenho o código como o seguinte:

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

Init init;

Idealmente, eu gostaria de ser capaz de simplesmente escreve:

initialize();

Mas isso não compilação ...

Existe uma menos extenso caminho para conseguir o mesmo efeito?

Nota:. o código é parte de um esboço Arduino então a função main é gerado automaticamente e não podem ser modificados (por exemplo, para initialize chamada antes de qualquer outro código)

Update:. idealmente a inicialização seria realizada na função setup, mas neste caso há outro código dependendo isso que ocorre antes main

Foi útil?

Solução

Você pode usar o atributo do GCC constructor para garantir que ele é chamado antes main():

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

Outras dicas

Você pode fazer o acima muito ligeiramente mais curto, dando "inicializar" um tipo de retorno, e usando isso para inicializar uma variável global:

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

No entanto, você precisa ter cuidado com isso, o padrão não garante que a inicialização acima (ou um para o seu objeto de inicialização) acontece antes principal é executado (3.6.2 / 3):

É definido implementação-se ou não a inicialização dinâmica (8.5, 9.4, 12.1, 12.6.1) de um objeto do escopo namespace é feito antes da primeira declaração da principal.

A única coisa que é garantido é que a inicialização ocorrerá antes 'fictício' é sempre utilizada.

Uma opção mais intrusiva (se é possível) pode ser usar "-d principais = avr_main" em seu makefile. Você pode então adicionar seus próprios principal da seguinte forma:

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

Pelo menos aqui você tem a garantia de que a inicialização ocorrerá quando você espera.

Aqui está um método um tanto mal de conseguir isso:

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

Adicione o seguinte para as bandeiras vinculador: --wrap main

por exemplo.

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

O vinculador irá substituir todas as chamadas para main com chamadas para __wrap_main, consulte a ld página homem em --wrap

A sua solução em simples e limpo. O que você pode adicionalmente fazer é colocar o seu código no namespace anônimo. Eu não vejo qualquer necessidade de torná-lo melhor do que isso:)

Se você estiver usando o ambiente Arduino, há alguma razão que você não pode colocá-lo na configuração método ?

Claro, isso é, após a configuração de hardware específicos do Arduino, então se você tem essas coisas de baixo nível que ele realmente tem que ir antes main, então você precisa de um pouco de magia construtor.

UPDATE:

Ok, se ele tem que ser feito antes da principal Acho que a única maneira é usar um construtor como você já faz.

Você pode sempre fazer uma macro pré-processador dele:

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

Agora, isso deve funcionar:

RUN_EARLY(initialize())

Mas não é realmente fazer as coisas mais curto, apenas movendo o código detalhado ao redor.

Você pode usar o ".init *" seções para adicionar o código C para ser executado antes de main () (e até mesmo o tempo de execução C). Estas secções são ligados no executável no final e chamou-se a uma hora específica durante a inicialização do programa. Você pode obter a lista aqui:

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

.init1 por exemplo, é fracamente ligada a __init (), então se você definir __init (), ele será ligado e chamado primeira coisa. No entanto, a pilha não foi configurado, então você tem que ter cuidado no que você faz (somente usar variável register8_t, não chamar quaisquer funções).

Utilize membros estáticos de classes. Eles são inicializados antes de entrar para principal. A desvantagem é que você não pode controlar a ordem da inicialização dos membros da classe estática.

Aqui é o seu exemplo 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;

Claro, você colocar isso em um de seus seus arquivos de cabeçalho, dizem preinit.h:

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

e, em seguida, em um de suas unidades de compilação, colocar:

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

Eu sei que é um truque, mas eu não estou ciente de qualquer maneira portátil para fazer a inicialização pré-principal sem usar um construtor de classe executado no escopo do arquivo.

Você também deve ter o cuidado de incluir mais de uma dessas funções de inicialização desde que eu não acredito ditames C ++ a ordem -. Que poderia ser aleatória

Eu não tenho certeza disso "esboço" de que você fala, mas seria possível transformar a unidade de compilação principal com um script antes de tê-lo passado para o compilador, algo como:

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

Você pode ver como isso afetaria seu 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();"
    }
}'

gera a seguinte com a chamada initialize() acrescentou:

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

Pode ser que você não pode pós-processo o arquivo gerado caso em que você deve ignorar que a opção final, mas isso é o que eu estaria olhando em primeiro lugar.

Não é como eu executar pré-main codificação. Há seções de inicialização Sever executados antes principal, refere-se a http: // www. nongnu.org/avr-libc/user-manual/mem_sections.html initN seções.

De qualquer forma, isso só funciona em -O0 otimização por algum motivo. Eu ainda tento descobrir qual opção "otimizado" minha pré-main código de montagem de distância.

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, não é que eu reivindicou esta função não é utilizada, levando a otimizar a rotina de distância. Eu tinha a intenção de matar função de advertência não utilizado. Ele é fixado ao atributo usado em seu lugar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top