如果我在嵌入式系统中定义宏或使用静态常量值,
将使用哪种存储器,芯片闪存还是芯片ram?哪种方式更好?
发布于 2012-03-23 10:54:38
好吧,如果你#定义一个宏,没有额外的内存或代码空间(flash)分配给它。所有工作都在编译阶段完成。
如果使用static const全局变量,将为初始值和为其分配的内存生成二进制代码。使用闪存(bin文件较大)和内存(芯片ram)。
发布于 2012-03-23 12:18:50
我相信答案会更复杂。
编辑:我很抱歉使用了“应该”和“可能”,但没有特定的编译器或调试器,我发现它必须准确和精确。也许如果问题可以说出目标是什么编译器和平台,我们就可以更清楚?
在出现在代码中之前,
#define NAME ((type_cast)value)不会占用任何空间。编译器可能能够使用它的值来推断某些东西(与使用具有未知运行时值的变量相比),因此可能会更改生成的代码,从而有效地不消耗任何空间,或者甚至可以减少代码的大小。如果编译器的分析是在运行时需要该字面值,那么它将消耗代码空间。字面值是已知的,因此编译器应该能够分配最佳的空间量。根据处理器的不同,它应该存储在闪存中,但可能不是内联代码,而是在“文字池”中,一组本地变量,通常靠近代码,因此可以使用紧凑的地址。编译器可能会使良好的decisions.static const type name = value;在代码中使用之前不会消耗空间。即使在代码中使用它,它也可能消耗“空间”,也可能不消耗“空间”,这取决于您的编译器(我认为是它正在编译的C标准)以及代码如何使用该值。如果名称的地址从未被获取过,那么编译器就不必存储它。如果该值的地址被获取(并且该代码没有被删除),则该值一定在内存中。智能编译器将检测源文件中是否有任何代码采用其地址。即使它可能被存储,编译器也可能通过不使用存储值来生成更好的(更快或更紧凑的代码)。
尽管编译器可能比#define更糟糕,但它可能会做得和#define NAME一样好。
如果该值的地址已取,则编译器将该变量视为已初始化的变量,这将消耗空间来存储常量值。编译器并不真正将值放入RAM或闪存中。这取决于链接器。在gcc中,有一些“属性”可以用来告诉链接器应该将变量放到哪个段中。默认情况下,编译器将初始化的变量放入缺省数据段,并将const初始化放入只读段。通过使用属性,程序员可以将变量放入任何段中。使用适当的链接器脚本(通常随工具链一起提供),片段可以放入flash中。对于文字字符串之类的数据,Gcc使用只读数据段。
name应该在调试器中可用,但#define NAME不能。
枚举常量{ name = 1234,height = 456 ... };
这些可能会被像#define constants这样的编译器处理,尽管它们不是很灵活,因为它们是int大小(IIRC)。没有办法获取枚举值的地址,因此编译器有许多选项来生成良好的代码和#define NAME。它们通常会在debugger.
const type name = value;中可用,可能会消耗内存。它必须在内存中,因为编译器无法知道其他文件中的代码是否使用了它,或者是否获取了它的地址(但gcc LTO可能会改变这一点)。const告诉编译器,如果任何代码试图更改值,就会发出警告(或错误),例如,使用赋值操作符。通常,内存中保存的变量存储在数据段或bss内存段中。默认情况下,gcc将数据段放入只读段,可以使用命令行选项-mrodata= const --mrodata=- .rodata来设置该段。该段在ARM上是.rodata。在嵌入式系统中,所有初始化的全局变量和静态变量(无论是否为const)都保存在闪存中,并在程序启动时(在调用main()之前)复制到内存中。在调用main()之前,所有未初始化的全局变量或静态变量都设置为0。
编译器可能会将const变量放入它们自己的内存段(gcc就是这样做的),这可能会允许链接器(例如ld)脚本将它们放入闪存,而不会为它们分配任何内存(这在使用不同指令从闪存加载数据的AVR ATmega上不起作用)。
发布于 2012-03-23 15:32:42
除了其他人所说的:
使用#define的
https://stackoverflow.com/questions/9833514
复制相似问题