为什么int a [5] = {0}和int a [5] = {1}(缺少功能)[闭合]之间的区别
-
23-10-2019 - |
题
当我们初始化这样的阵列时 int a[5] = {0}
, ,编译器制作所有5个元素0。
但是我想知道为什么编译器不初始化 int a[5]={1}
相似地?为什么不使所有5个元素1?为什么标准不要求它?这不是一个很棒的功能吗?不丢失吗?
同样,如果初始化器中的元素数小于数组的大小,则编译可以用初始化器中的最后一个元素初始化其余元素。方法, int a[5]={1,2,3}
等同于 int a[5]={1,2,3,3,3}
. 。同样, int a[10]={1,2,3,0}
等同于 int a[10]={1,2,3,0,0,0,0,0,0,0};
.
如果标准要求它,这不是一个很棒的功能吗?还是有什么充分的理由造成此丢失的功能?
还有一个叫做的东西 指定的初始化器 在C99中,它被使用:
指定的初始化器可以与常规初始化器结合使用,如以下示例:
int a[10] = {2, 4, [8]=9, 10}
在此示例中,a [0]初始化为2,a1 初始化为4,[2]至[7]的初始化为0,并且[9]初始化为10。
很有趣。但是,即使此功能也不在C ++中。
解决方案
我个人发现更多的“逻辑”(即简单)具有固定的默认初始化器,而不是仅用于数组的最后一个规则。这可能看起来“实用”(即有用),但在逻辑上更复杂。
也就是说,我认为您正在做一个 大的 试图将逻辑应用于C ++等语言的错误。
C ++是一种复杂的语言,其规则是长期进化历史的结果,其当前形式是许多人甚至正式委员会的工作的结果(仅最后一部分就可以解释 任何事物).
像C ++这样的语言不能通过逻辑来推断,必须像历史一样研究它。除非你 哈里·塞尔顿 实际上,您无法使用逻辑推理推断历史记录。
如果您尝试使用逻辑而不是学习,则在C ++的某些地方会遭受很多痛苦。仅举几个...
- 为什么默认调度静态(即 错误的)?
- 为什么没有零指针的关键字?
- 为什么两个未签名的差异是未签名的?
- 为什么签名和未签名之间的总和是未签名的?
- 如果未签名表示“ z_ {2^n}“那么为什么尺寸未签名?
- 为什么
std::string s; s=3.141592654;
完全有效的C ++吗? - 为什么在C ++ 0x中
i = i++ + 1;
是不确定的行为和i = ++i + 1;
已验证? - 为什么
double x=3.14; int y(int(x));
并不是说y
会3岁吗?
其他提示
为什么不使所有5个元素1?
因为你误会了什么 {}
方法。 (实际上,在C ++中,更好的方法是 {}
而不是 {0}
)。语法 {0}
并不意味着您希望将汇总设置为零。相反,它说您希望将第一个元素零分配给指示变量(可以是C ++中的阵列或类类型)。因为聚集体通常比一个值零具有更多的字段 默认构造. 。内置或POD类型的默认值是将所有字段设置为零,因此您将整个聚合物有效地设置为零。
至于为什么特别考虑以下内容。根据当前标准,以下任何断言都不会失败:
struct abc
{
char field1;
int field2;
char field3;
};
int main()
{
abc example = {'a', static_cast<int>('b')};
//All three asserts pass
assert(example.field1 == 'a');
assert(example.field2 == static_cast<int>('b'));
assert(example.field3 == '\0');
int example2[3] = {static_cast<int>('a'), 42};
assert(example2[0] == static_cast<int>('a'));
assert(example2[1] == 42);
assert(example2[2] == 0);
}
您期望的价值 field3
在您建议的标准更改中?即使您将其定义为如上所述的聚合初始化器中的最后一个元素,它也将与现有代码的兼容性打破,该代码假设其余元素是默认构建的。
编辑: 只是意识到您的问题是通过数组来提出的 - 但是结构或数组的答案是相同的,因此确实没关系。
edit2: 为了使其与标准保持一致,对类/结构的引用已被下面的“汇总”代替,该范围涵盖了结构和阵列案例。
是的,他们 可以 已经这样做了,但是他们没有,现在改变这种行为为时已晚。 C和C ++背后的决定几乎是对性能和极简主义的思想做出的,因此我想,如果没有其他事情,也没有其他作用。
这样的功能并没有让我如此出色。这是一件非常简单的句法糖,我很少发现需要将类似的数组初始化为0的任何东西。
典型的运行时库提供了一项功能,可轻松初始化数据到0。总的来说,这是在特定的 部分 在可执行文件中,由编译器和链接器组织。在程序启动时,运行时启动代码使用类似 memset()
将所有初始数据清除到0。这意味着零字节不必存储在可执行文件内部。
相反的是,如果您将数据初始化为某物 以外 零,然后该数据的字节必须存储在可执行文件本身中,因为自动启动器的初始评估仅为零。
因此,如果您要声明一大批 char
(说一个兆字节?) {0}
, ,然后不会在该数组的可执行文件中存储字节。另一方面,如果您要使用它 {1}
根据您的计划, 1
字节必须存储在可执行文件中。通过更改初始评估列表中的一个字符,可执行文件的大小增加了兆字节。
我相信这样的计划会违反 至少令人惊讶的原则.