如何使用avr-gcc在C/C++中执行主前期初始化?

问题描述:

为了确保一些初始化代码之前main(使用的Arduino/AVR-GCC)我有代码运行,如下所示:如何使用avr-gcc在C/C++中执行主前期初始化?

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

Init init; 

理想情况下,我想能够简单地写:

initialize(); 

但这并不编译...

有没有一种更简洁的方式来达到同样的效果?

注:的代码是一个Arduino草图所以自动生成main功能的一部分并且不能被修改(例如,以任何其他代码之前调用initialize)。

更新:理想初始化将在setup功能来执行,但在这种情况下,是依赖于它的其他代码main之前发生。

您可以使用GCC的constructor attribute以确保它被调用之前main()

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

您的解决方案简单而干净。你可以额外做的是把你的代码放在匿名的命名空间中。我看不出有任何需要,使之比:)更好

+0

将它包装在一个匿名命名空间中可能会阻止该类及其实例的名称对命名空间造成污染(这是件好事),但它并不能真正帮助减少代码的冗长... – 2009-06-04 11:45:35

当然,你把这个在你的头文件中的一个,说preinit.h:

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

,然后在一个您编译单元,放:

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

我知道这是一个杂牌组装电脑,但我不知道任何便携式方式做前期主流初始化,而不使用在文件范围内执行的类的构造函数。

由于我不相信C++规定了顺序 - 它可能是随机的,所以您还应该小心地包含多个这些初始化函数。

我不知道的,其中你说这“小品”,但它会为它传递到编译器之前,可以对主编译单元使用脚本转换,是这样的:

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

解决方案没有' t需要是便携式的。它只需要使用avr-gcc工作。 – 2009-06-04 11:52:45

使用类的静态成员。它们在进入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; 
+3

这是更详细的,不是更少。 – 2009-06-04 11:18:47

+0

这个想法让我想知道是否在C++中定义了静态成员在类*层次结构*中的初始化顺序?如果是这样,将是一种解决“静态初始化顺序失败”的方法。 – 2009-06-04 12:11:09

+0

@Piotr:翻译单元中初始化的顺序被定义为“定义出现的顺序”。翻译单位之间未定义。 – 2009-06-04 13:33:57

如果您使用的是Arduino的环境下,没有任何理由,你不能将它放在setup method

当然,这是在Arduino特定的硬件设置之后,所以如果你有这样的低级别的东西,它必须在main之前去,那么你需要一些构造魔术。

UPDATE:

好吧,如果它做之前,主要我认为唯一的方法是使用一个构造像你已经做的。

您可以随时在它的预处理宏:

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

现在,这应该工作:

RUN_EARLY(initialize()) 

但它并不是真正使事情更短,只需移动冗长的代码周围。

+0

+1,但不幸的是我无法使用setup()。我会更新这个问题来说明问题。 – 2009-06-04 11:43:12

您可以通过给“初始化”返回类型,并用它来初始化一个全局变量上面非常稍短:

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

但是,你必须要小心一点,标准不不保证上面的初始化(或初始化对象的初始化)在main运行之前发生(3.6.2/3):

它是实现定义是否动态初始化(8.5,9.4 ,12.1,12.6.1)是在mai的第一个语句之前完成的ñ。

唯一可以保证的是初始化将在“虚拟”被使用之前发生。

一个更具侵入性的选项(如果可能的话)可能是在makefile中使用“-D main = avr_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); 
} 

至少在这里你保证,当你希望初始化会发生。

这里是实现这一目标的一个有点邪恶方法:

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

添加以下链接标志:--wrap main

如。

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

连接器将通过调用替换所有呼叫main__wrap_main,看到ld man page--wrap

你可以使用“.init *”部分添加要在main()(甚至C运行时)之前运行的C代码。这些部分在最后连接到可执行文件,并在程序初始化期间的特定时间调用。你可以在这里获取列表:

例如

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

.init1微弱结合到__init(),所以如果你定义__init(),它会被链接并要求第一件事情。然而,堆栈还没有建立,所以你必须小心你的操作(只使用register8_t变量,不要调用任何函数)。

有我如何执行pre-main编码。 在main之前执行了严重的init部分,指的是http://www.nongnu.org/avr-libc/user-manual/mem_sections.html initN部分。

无论如何,这只适用于-O0优化出于某种原因。我仍然试图找出哪些选项“优化”了我的主要汇编代码。

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

更新,事实证明,我声称这个功能是未使用的,导致优化程序。我打算杀死功能未使用的警告。反而固定到使用过的属性。