我正在使用 C 编写的库,我自己的程序在 C ++ 中。他们 typedef 这样的结构:
typedef struct tagCtxt
{
char iadl1[50+1];
char iadl2[50+1];
char iprurb[28+1];
char iadl3[50+1];
} PARM;
在我的一个方法中,我构造它并立即打印其中一个字段的值:
PARM parm1;
cout << "'" << parm1.iadl3 << "'" << endl;
正如所料,它是空白/空白:
''
现在我这样做,创建parm2
:
PARM parm1, parm2;
cout << "'" << parm1.iadl3 << "'\t'" << parm2.iadl3 << "'" endl;
然后我明白了:
'' 'x��'
第二个的输出有所不同。有时它看起来像XŰ
或8ư
或�ǰ
或ǰ
等。
此行似乎可以解决症状:
memset(&parm2.iadl3, 0, sizeof(parm2.iadl3));
但问题是什么?为什么char数组非空为第二个?而不是第一个?
请记住,我的程序编译为 C ++ 但我正在使用的头文件定义的类型在 C 中。这有什么区别吗?我像这样包含头文件:
extern "C"
{
#include "parm.h"
}
答案 0 :(得分:4)
这是undefined behavior,自动变量的初始值是不确定的,您需要在使用它们之前初始化变量。
<{1}}部分<{1}} 对象的存储持续时间在覆盖静态变量之后说(强调我的 ):
对于没有可变长度数组类型的对象,其生命周期会延长 从进入与之关联的块直到该块的执行结束 无论如何。 [...] 对象的初始值是不确定的。 [...]
indeterminate value 的定义如下:
未指定的值或陷阱表示
C99 draft standard部分6.2.4
初始化段 12 表示(强调我的):
如果没有为对象指定初始化程序,则默认初始化该对象;如果未执行初始化,具有自动或动态存储持续时间的对象具有不确定值。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见3.6.2。 - 后注]
开始理解某些形式的未定义行为的好地方是C++ draft standard幻灯片。
答案 1 :(得分:2)
“正如预期的那样,它是空白/空的:”不,这不是预期的。 C ++没有初始化变量的值(除了它的数据类型提供了一个构造函数来完成这项工作,或者是一个具有静态存储持续时间的东西)。
正如沙菲克所说,阅读未初始化的数据有不明确的行为。
答案 2 :(得分:1)
与C / C ++无关。
一般情况下,你没有明确设置的内存(比如你所做的memset
操作)包含未定义的值。
“预期”不是0。
答案 3 :(得分:1)
C和C ++不保证局部变量的值。它们具有垃圾值,具体取决于分配时该内存地址的内容。要使用它们,必须使用值初始化它们。
全局变量不是这样。默认情况下,它们初始化为0。
答案 4 :(得分:1)
char iadl1[50+1];
将保留一块足以存储51个字符的内存块
但是,它并不能保证你的那块内存都是空的,在你的情况下恰好是空的。通常,在访问数组之前使用memset来初始化数组是最好的方法。
memset( iadl1, '\0', sizeof(char)*51);
答案 5 :(得分:1)
只有静态变量具有预初始化的值。在堆栈上创建的变量(即局部变量)具有垃圾值,因此在初始化之前不应使用。
答案 6 :(得分:0)
一种方法是定义构造函数来初始化参数
typedef struct tagCtxt
{
tagCtxt()
{
memset( iadl1, '\0', sizeof(char)*51);
memset( iadl2, '\0', sizeof(char)*51);
memset( iprurb, '\0', sizeof(char)*29);
memset( iadl3, '\0', sizeof(char)*51);
}
char iadl1[50+1];
char iadl2[50+1];
char iprurb[28+1];
char iadl3[50+1];
} PARM;