我有一堆全局变量,我喜欢用特定的函数初始化,比如:
// MyFile.h
typedef struct myValues
{
int a;
int b;
int c;
} myValuesType;
extern myValuesType values[5];
void Initialize(void);
// MyFile.c
myValuesType values[5];
// This gets called in main() before everything else
void Initialize(void)
{
values[0].a = 1;
values[0].b = 2;
values[0].c = 3;
// ETC
}
然而,我遇到了一些直接在定义中进行初始化的代码,比如:
// MyFile.h
typedef struct myValues
{
int a;
int b;
int c;
} myValuesType;
extern myValuesType values[];
// MyFile.c
myValuesType values[] =
{
{0,1,2},
// Etc.
}
对我来说,对于这个特定的例子,第二个实现要精简得多,可能更干净,但我最感兴趣的是实际发生的事情:两者之间的区别是什么?
我是不是在没有任何值的情况下定义它们,然后调用一个函数来初始化它们,从而让计算机做更多的事情?
在第二种情况下,是编译器在做这项工作吗?在很大程度上,这会导致代码得到优化?
最后,第二种实现并不总是适用的,对吧?比如,如果我需要将它们初始化为函数返回的值,或者如果我需要对值进行malloc(或者你想到的任何其他情况(,我需要创建一个函数来初始化它们,对吧?
但对于我发布的代码片段,有什么更好的方法来处理它呢?
我是不是在没有任何值的情况下定义它们,然后调用一个函数来初始化它们,让计算机做更多的事情?
是。编译器将在.exe文件中创建一个函数,将值写入变量(因为这是你告诉编译器要做的(,计算机将在程序运行时运行它。
为了澄清:编译器将在exe文件中创建Initialize函数。一位评论者认为我的意思是编译器会自动创建一个额外的函数
在第二种情况下,是编译器在做这项工作吗?在很大程度上,这会导致代码得到优化?
是。编译器只需将值直接写入该变量的数据部分中的.exe文件中。在操作系统加载.exe文件后,这些值将已经存在,计算机不必做任何额外的操作。此外,这些值直接在它们的最终布局中,而对于第一个选择,函数基本上由一长串"组成;把这个值放在这个地址";这意味着地址也必须被处理。
最后,第二个实现并不总是适用的,对吧?比如,如果我需要将它们初始化为函数返回的值,或者如果我需要对值进行malloc(或者你想到的任何其他情况(,我需要创建一个函数来初始化它们,对吧?
是的,没错。第二个仅适用于在编译时知道所有值的情况。
在C++(您没有使用(中,您总是可以使用第二个,尽管编译器只是在它不工作时将其转换为第一个。如果需要,编译器会在main
之前插入函数调用,如果函数被声明为constexpr
,有时也可能在编译时运行这些函数。
将我的评论转换为答案
您的第一个代码不是";初始化";变量——它们被初始化为全零(因为没有显式初始化器(,并且您的代码在程序运行后为它们分配其他值。
尽可能使用第二个示例中的初始值设定项,这样更简单、更高效。当您使用初始化时,系统不会加载所有字节为零的数据,然后在函数调用中覆盖内存。此外,没有办法避免正确初始化内存,而使用函数调用时,您可能会忘记调用它,将内存保留为";所有字节为零";。
然而,如果您还需要将全局变量重置为已知的"0";并非所有字节都为零";状态,那么函数可能是更好的选择——但你可能也需要问问自己";为什么我有全局变量需要这样(重新(初始化">
如果初始化必须使用函数调用,或者需要分配动态内存,则必须使用初始化函数。