用C ++初始化数组

我看到的每个地方都有人大声争辩说未经初始化的变量是坏的,我当然同意并理解为什么 – 但是; 我的问题是,有时候你不想这样做吗?

例如,取代码:

char arrBuffer[1024] = { '\0' }; 

对整个arrays执行NULL操作是否会在不初始化的情况下使用arrays产生性能影响?

我假设堆栈初始化,因为静态数组是自动初始化的。
G ++输出

  char whatever[2567] = {'\0'}; 8048530: 8d 95 f5 f5 ff ff lea -0xa0b(%ebp),%edx 8048536: b8 07 0a 00 00 mov $0xa07,%eax 804853b: 89 44 24 08 mov %eax,0x8(%esp) 804853f: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) 8048546: 00 8048547: 89 14 24 mov %edx,(%esp) 804854a: e8 b9 fe ff ff call 8048408  

因此,您使用{‘\ 0’}初始化并完成对memset的调用,所以是的,您的性能会受到影响。

如果变量是全局变量或静态变量,则其数据通常逐字存储在已编译的可执行文件中。 因此,您的char arrBuffer[1024]将增加1024字节的可执行文件大小。 初始化它将确保可执行文件包含您的数据,而不是默认的0或编译器选择的任何内容。 程序启动时,不需要处理来初始化变量。

另一方面,堆栈上的变量(例如非静态本地函数变量)不会以相同的方式存储在可执行文件中。 相反,在函数入口上,空间在堆栈上分配,memcpy将数据放入变量中,从而影响性能。

规则是变量应该在使用之前设置。

如果您知道在使用之前将其他设置在其他位置,则无需在创建时显式初始化它们。

例如,以下代码完全没问题:

 int main (void) { int a[1000]; : : for (int i =0; i < sizeof(a)/sizeof(*a); i++) a[i] = i; : : // Now use a[whatever] here. : : return 0; } 

在这种情况下,在创建数组时初始化数组是浪费的。

至于是否存在性能损失,它部分取决于您的变量的定义位置,部分取决于执行环境。

C标准保证用静态存储持续时间(在文件级别或在函数中作为静态)定义的变量首先初始化为全零的位模式,然后设置为它们各自的初始化值。

没有强制如何完成第二步。 一种典型的方法是让编译器本身创建初始化变量并将其放在可执行文件中,以便通过加载可执行文件来初始化它。 这对性能没有影响(对于初始化,显然它会对程序负载产生一些影响)。

当然,实现可能希望节省可执行文件中的空间并使用代码初始化这些变量(在调用main之前)。 这产生性能影响,但可能是微不足道的。

对于那些具有自动存储持续时间的变量(局部变量等),除非你为它们分配内容,否则它们永远不会被隐式初始化,因此也会对性能造成损失。 通过“从不隐式初始化”,我的意思是代码段:

 void x(void) { int x[1000]; ... } 

将导致x []具有不确定的值。 但是由于:

 void x(void) { int x[1000] = {0}; } 

可能只会导致1000整数的memcpy类型操作(更可能是针对该情况的memset),这也可能很快。 您只需要记住, 每次调用该函数时都会发生初始化。

测量!

 #include  #include  int main(void) { clock_t t0; int k; t0 = clock(); for (k=0; k<1000000; k++) { int a[1000]; a[420] = 420; } printf("Without init: %f secs\n", (double)(clock() - t0) / CLOCKS_PER_SEC); t0 = clock(); for (k=0; k<1000000; k++) { int a[1000] = {0}; a[420] = 420; } printf(" With init: %f secs\n", (double)(clock() - t0) / CLOCKS_PER_SEC); return 0; } 
 $ gcc measure.c
 $ ./a.out
没有init:0.000000秒
   使用init:0.280000秒
 $ gcc -O2 measure.c
 $ ./a.out
没有init:0.000000秒
   使用init:0.000000秒

对于大型arrays,性能影响可能很大。 默认情况下,所有变量的初始化实际上并没有带来很多好处。 它不是坏代码的解决方案,而且它可能隐藏可以被编译器捕获的实际问题。 您需要在整个生命周期中跟踪所有变量的状态,以使代码可靠。

回答你的问题:它可能会对性能产生影响。 编译器可能会检测到数组的值未使用而只是不执行它们。 这是可能的。

我个人认为这是个人风格的问题。 我很想说:保持未经初始化,并使用类似Lint的工具告诉你是否使用它未经初始化,这肯定是一个错误(而不是使用默认值而不被告知,这也是一个错误,但一个无声的)。

我认为要求所有变量在声明时默认初始化是一个不好的建议。 在大多数情况下,这是不必要的并且会带来性能损

例如,我经常使用下面的代码将数字转换为字符串:

 char s[24]; sprintf(s, "%d", int_val); 

我不会写:

 char s[24] = "\0"; sprintf(s, "%d", int_val); 

现代编译器能够判断变量是否在未初始化的情况下使用。

您的变量应初始化为有意义的值。 盲目而天真地将一切设置为零并不比将其保持未初始化好得多。 它可能会导致无效代码崩溃,而不是表现不可预测,但它不会使代码正确

如果在创建数组时只是天真地将数组清零以避免未初始化的变量,那么它在逻辑上仍然是未初始化的。 它还没有在您的应用程序中有意义的值。

如果您要初始化变量(并且您应该),请为它们提供在您的应用程序中有意义的值。 你的其余代码是否期望数组最初为零? 如果是,请将其设置为零。 否则将其设置为其他有意义的值。

或者如果你的代码的其余部分希望写入数组,而不先读取它,那么一定要保持未初始化。

就个人而言,我反对在创建时初始化一个数组。 考虑以下两段代码。

 char buffer[1024] = {0}; for (int i = 0; i < 1000000; ++i) { // Use buffer } 

 for (int i = 0; i < 1000000; ++i) { char buffer[1024] = {0}; // Use buffer } 

在第一个例子中,为什么要打扰初始化缓冲区,因为循环缓冲区周围的第二次不再是0初始化? 除了第一次迭代之外,我对缓冲区的使用必须在没有被初始化的情况下工作。 所有初始化都会耗费时间,膨胀代码并掩盖错误,如果通常我只通过循环一次。

虽然我当然可以将代码重新考虑为第二个例子,但是如果我可以重新编写代码而不是必要的话,我是否真的想在循环内初始化缓冲区?

我怀疑这些天大多数编译器都有选项来填充非0值的未初始​​化变量。 我们以这种方式运行所有调试版本,以帮助检测未初始化变量的使用,并且在发布模式下,我们关闭选项,以便变量真正未初始化。 正如Sherwood Hu所说,一些编译器可以注入代码来帮助检测未初始化变量的使用。

编辑:在上面的代码中,我将缓冲区初始化为值0(不是字符'0'),这相当于用'\ 0'初始化它。

为了进一步阐明我的第一个代码片段,想象下面的设计示例。

 char buffer[1024] = {0}; for (int i = 0; i < 1000000; ++i) { // Buffer is 0 initialized, so it is fine to call strlen int len = strlen (buffer); memset (buffer, 'a', 1024); } 

第一次通过循环时缓冲区初始化为0,因此strlen将返回0.第二次通过循环时缓冲区不再初始化为0,实际上不包含单个0字符,因此strlen的行为未定义。

因为你同意我的意见,如果初始化缓冲区,不建议在循环内部移动缓冲区,并且我已经certificate在循环外部初始化它不提供保护,为什么要初始化它?

为什么你要关心性能优势,通过不初始化它会获得多少性能,并且由于垃圾指针,它比调试期间节省的时间更多。