当前位置:  开发笔记 > 编程语言 > 正文

初始化对象时{0}意味着什么?

如何解决《初始化对象时{0}意味着什么?》经验,为你挑选了6个好方法。

何时{0}用于初始化对象,这是什么意思?我找不到任何{0}地方的任何引用,并且由于大括号,谷歌搜索没有帮助.

示例代码:

SHELLEXECUTEINFO sexi = {0}; // what does this do?
sexi.cbSize = sizeof(SHELLEXECUTEINFO);
sexi.hwnd = NULL;
sexi.fMask = SEE_MASK_NOCLOSEPROCESS;
sexi.lpFile = lpFile.c_str();
sexi.lpParameters = args;
sexi.nShow = nShow;

if(ShellExecuteEx(&sexi))
{
    DWORD wait = WaitForSingleObject(sexi.hProcess, INFINITE);
    if(wait == WAIT_OBJECT_0)
        GetExitCodeProcess(sexi.hProcess, &returnCode);
}

没有它,上面的代码将在运行时崩溃.



1> Don Neufeld..:

这里发生的事情称为聚合初始化.以下是ISO规范第8.5.1节中聚合的(缩写)定义:

聚合是一个数组或类,没有用户声明的构造函数,没有私有或受保护的非静态数据成员,没有基类,也没有虚函数.

现在,使用{0}像这样初始化聚合基本上是0整个事情的一个技巧.这是因为在使用聚合初始化时,您不必指定所有成员,并且规范要求默认初始化所有未指定的成员,这意味着设置0为简单类型.

以下是规范的相关引用:

如果列表中的初始值设定项少于聚合中的成员,则未明确初始化的每个成员都应默认初始化.例:

struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };

初始化ss.awith 1,ss.bwith "asdf"ss.cwith表达式的表达式int(),即 0.

您可以在此处找到有关此主题的完整规范


@Branan,那是因为C"{}"无效.在C++中它是.@ don.neufeld,这已经改变了C++ 03(默认初始化 - >值初始化).请注意引用C++ 98标准.
出色的回应.只是想补充一点,用{0}初始化聚合与用{}初始化它是一样的.也许前者使得内置类型变得更加明显.
不完全..在C++中,如果第一个成员不能构造为零,则{0}将不起作用.例如:结构A {B b; int i; char c; }; struct B {B(); B(字符串); }; A = {}; //此语句不能重写为"A a = {0}".
有些编译器会阻塞{},这就是使用{0}的原因
那么,这是否取代了使用ZeroMemory()(在VC++中)的需要?

2> Harold Ekstr..:

需要注意的一点是,这种技术不会将填充字节设置为零.例如:

struct foo
{
    char c;
    int  i;
};

foo a = {0};

不一样:

foo a;
memset(&a,0,sizeof(a));

在第一种情况下,c和i之间的填充字节是未初始化的.你为什么要关心?好吧,如果您将此数据保存到磁盘或通过网络或其他任何方式发送,则可能存在安全问题.


应该注意的是,虽然规范不需要初始化填充,但任何理智的编译器都会,因为它只需要花费时间来"初始化"它.
当然,如果你写(f,&a,sizeof(a))',这只会是一个安全问题,它可以在不同的处理器/编译器上产生不同的文件编码.格式良好的输出在没有memset的情况下是安全的.
我想用"不是"这个词来解决问题.填充字节是实现定义的.编译器可以自由地将foo a = {0}转换为memset(&a,0,sizeof(a)).不需要"跳过"填充字节和*仅*设置foo.c和foo.i. (潜在的)安全漏洞的+1
此外,如果您通过网络发送内容,则始终将对齐设置为打包.这样,您可以获得尽可能少的额外填充字节.
@Leushenko第19点说"所有未明确初始化的子对象",所以我倾向于第21点(你引用的)是草率的.如果规范允许填充在最后一个初始化器的时刻之前未被初始化,之后填充必须归零,这将是非常奇怪的,特别是考虑到当使用指定的初始化器时初始化器可能出现乱序.
@HaroldEkstrom对此答案的更新:从C11和C++ 11开始,通过此方法明确要求填充位设置为零.
@MM实际上你是对的,对填充的显式引用是关于静态对象的部分; 但是"聚合的其余部分应与具有静态存储持续时间的对象隐式初始化"(C11 6.7.9).我想在技术上你可以扭曲这意味着跳过填充位*iff*你为所有成员提供显式初始化器,但这需要编译器供应商竭尽全力来哄骗你.模糊的文本,但我认为意图是填充是零.

3> dalle..:

请注意,空聚合初始化程序也有效:

SHELLEXECUTEINFO sexi = {};
char mytext[100] = {};



4> snowcrash09..:

回答为什么ShellExecuteEx()崩溃:你的SHELLEXECUTEINFO"sexi"结构有很多成员,你只是初始化其中的一些.

例如,成员sexi.lpDirectory可能指向任何位置,但ShellExecuteEx()仍会尝试使用它,因此您将获得内存访问冲突.

当您包含该行时:

SHELLEXECUTEINFO sexi = {0};

在你的结构设置的其余部分之前,你告诉编译器在你初始化你感兴趣的特定结构之前将所有结构成员清零.ShellExecuteEx()知道如果sexi.lpDirectory为零,它应该忽略它.



5> Adam Pierce..:

我也用它来初始化字符串,例如.

char mytext[100] = {0};


当然,如果mytext被用作字符串,我的文字[100]; mytext [0] ='\ 0'; 给出一个空字符串具有相同的效果,但只会导致实现将第一个字节归零.

6> Keith Thomps..:

{0}是C和C++中任何(完整对象)类型的有效初始值设定项.这是用于将对象初始化为零的常用习惯用法(请继续阅读以了解其含义).

对于标量类型(算术和指针类型),大括号是不必要的,但它们是明确允许的.引用ISO C标准的N1570草案,第6.7.9节:

标量的初始值设定项应为单个表达式,可选择用大括号括起来.

它将对象初始化为零(0对于整数,0.0对于浮点,指针的空指针).

对于非标量类型(结构,数组,联合),{0}指定将对象的第一个元素初始化为零.对于包含结构,结构数组等的结构,这是递归应用的,因此第一个标量元素设置为零,适用于类型.与任何初始化程序一样,未指定的任何元素都设置为零.

中间括号({,})可以省略; 例如,这些都是有效的和等效的:

int arr[2][2] = { { 1, 2 }, {3, 4} };

int arr[2][2] = { 1, 2, 3, 4 };

这就是为什么你不必编写例如{ { 0 } }第一个元素是非标量的类型的原因.

所以这:

some_type obj = { 0 };

是一种初始化obj为零的简写方式,这意味着如果每个标量子对象obj0一个整数(0.0如果它是浮点数),则设置为每个标量子对象,如果它是一个指针,则设置为空指针.

C++的规则类似.

在您的特定情况下,由于您要将值分配给sexi.cbSize等等,很明显它SHELLEXECUTEINFO是一个结构或类类型(或者可能是一个联合,但可能不是),所以并非所有这些都适用,但正如我所说的那样{ 0 }是常见的可以在更一般的情况下使用的习语.

不一定(必然)等同于使用memset将对象的表示设置为all-bits-zero.浮点0.0和空指针都不一定表示为全比特零,并且{ 0 }初始化器不一定将填充字节设置为任何特定值.但是,在大多数系统中,它可能会产生相同的效果.

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有