为什么 int a[5] = {0} 和 int a[5]={1} 之间存在差异(缺少功能)

发布于 2024-10-13 19:52:08 字数 1042 浏览 7 评论 0 原文

当我们初始化一个像 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};。

如果标准强制要求的话,这不是一个很棒的功能吗?或者这个缺失的功能有什么充分的理由吗?


还有一个叫做 指定初始化器,其用法如下:

指定的初始化器可以是 与常规初始化器结合,如 在以下示例中:

int a[10] = {2, 4, [8]=9, 10}

在这个 例如,a[0] 初始化为 2, a1初始化为4,a[2]初始化为a[7] 初始化为 0,a[9] 为 初始化为10。

很有趣。但即使这个功能在 C++ 中也没有。

When we initialize an array like this int a[5] = {0}, the compiler makes all 5 elements 0. That is really good, compact-initialization and useful feature.

But I wonder why the compiler doesn't initialize int a[5]={1} similarly? Why does it not make all 5 elements 1? Why the Standard doesn't mandate it? Would it not been an awesome feature? Isn't it missing?

Also, if the number of elements in the initializer is less than the size of the array, then the compile could initialize the remaining elements with the last element in the initializer. Means, int a[5]={1,2,3} is equivalent to int a[5]={1,2,3,3,3}. And similarly, int a[10]={1,2,3,0} is equivalent to int a[10]={1,2,3,0,0,0,0,0,0,0};.

Would it all not be an awesome feature if the Standard mandates it? Or is there any good reasons for this missing feature?


And there is something called designated initializer in C99, which is used like:

Designated initializers can be
combined with regular initializers, as
in the following example:

int a[10] = {2, 4, [8]=9, 10}

In this
example, a[0] is initialized to 2,
a1 is initialized to 4, a[2] to a[7]
are initialized to 0, and a[9] is
initialized to 10.

Quite interesting. But even this feature is not in C++.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浮光之海 2024-10-20 19:52:08

为什么它不使所有 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 的值是多少?即使您将其定义为聚合初始值设定项中的最后一个元素,如上面所示,这也会破坏与现有代码的兼容性,现有代码假设其余元素是默认构造的。


编辑:刚刚意识到您的问题是根据数组提出的 - 但答案对于结构或数组都是相同的,所以这并不重要。

编辑2:为了使其更符合标准,对类/结构的引用已替换为下面的“聚合”,其中涵盖了结构和数组情况。

Why does it not make all 5 elements 1?

Because you're misunderstanding what {} means. (Actually, in C++ the better way to do this is {} rather than {0}). The syntax {0} does not mean that you want all elements in the aggregate set to zero. Rather, it says that you want an aggregate with the first element zero assigned to the indicated variable (which can be either an array or a class type in C++). Because the aggregate usually has more fields than that one value zero, the remaining elements in the aggregate are default constructed. The default value of a builtin or POD type is to set all of the fields to zero, so you've effectively set the entire aggregate to zero.

As for why specifically, consider the following. According to the current standard, none of the assertions below will fail:

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);
}

What would you expect the value of field3 to be in your proposed standard change? Even if you define it as the last element in the aggregate initializer as you've shown above, that's going to break compatibility with existing code which assumes the rest of the elements are default constructed.


EDIT: Just realized that your question is asked in terms of arrays - but the answer is the same with either structures or arrays, so it really doesn't matter.

EDIT2: To make this more in keeping with the standard, references to class/structure have been replaced with "aggregate" below, which covers the structures and arrays cases.

不必在意 2024-10-20 19:52:08

是的,他们可以这样做,但他们没有,而且现在改变这种行为已经太晚了。 C 和 C++ 背后的决定几乎在每一步都考虑到了性能和极简主义,所以我想,如果没有其他的话,这里也会发挥作用。

这样的功能并没有让我觉得那么棒。这是一个非常简单的语法糖,而且我很少发现需要将这样的数组初始化为 0 以外的任何值。

Yes, they could have done that, but they didn't, and it's far too late now to change such behavior. The decisions behind C and C++ were made with thought given to performance and minimalism at almost every step, so I imagine that, if nothing else, comes into play here as well.

Such a feature just doesn't strike me as all that awesome. It's a very simple piece of syntactic sugar, and I rarely find the need to initialize an array like that to anything other than 0 anyway.

爱你不解释 2024-10-20 19:52:08

典型的运行时库提供了一种功能,可以轻松地将数据初始化为 0。一般来说,它存储在可执行文件中的特定部分中,由编译器和链接器组织。在程序启动时,运行时启动代码使用类似 memset() 的方法将所有初始化数据清除为 0。这意味着零字节不必存储在可执行文件本身内。

相反,如果您将数据初始化为零以外的值,则该数据的字节必须存储在可执行文件本身中,因为自动初始化程序仅初始化为零。

因此,如果您要声明一个大的 char 数组(比如兆字节?)并用 {0} 初始化它,那么就不会存储字节在该数组的可执行文件中。另一方面,如果您要在您的方案下使用 {1} 对其进行初始化,则必须将 1 MB 的 1 字节存储在可执行文件本身中。通过更改初始化列表中的一个字符,可执行文件的大小会增加一兆字节。

我相信这样的计划会违反最小意外原则

Typical runtime libraries provide a feature that makes it easy to initialise data to 0. In general terms, this is stored in a specific section in the executable, organised by the compiler and linker. At program startup, the runtime startup code uses something like memset() to clear out all the initialised data to 0. This means that the zero bytes don't have to be stored inside the executable itself.

The converse is that if you initialise data to something other than zero, then the bytes for that data must be stored in the executable itself, since the automatic initialiser only initialises to zero.

Therefore, if you were to declare a big array of char (say a megabyte?) and initialise it with, say, {0}, then there would not be bytes stored in the executable for that array. On the other hand, if you were to initialise it with {1} under your scheme, a megabyte of 1 bytes would have to be stored in the executable itself. By changing one character in the initialiser list, the size of the executable increases by a megabyte.

I believe such a scheme would violate the principle of least surprise.

余生一个溪 2024-10-20 19:52:08

我个人发现更“逻辑”(即简单)有一个固定的默认初始值设定项,而不是仅对数组重复最后一个规则的另一条规则。这可能看起来“实用”(即有用),但在我看来,它在逻辑上更复杂。

尽管如此,我认为您在尝试将逻辑应用于 C++ 这样的语言时犯了一个错误。

C++是一门复杂的语言,它的规则是长期演化历史的结果,它目前的形式是许多人甚至正式委员会工作的结果(仅最后一部分就可以解释任何) 。

像C++这样的语言不能通过逻辑推理,必须像历史一样研究它。除非你是Hari Seldon,否则你真的无法使用逻辑推理来推断历史。

如果你尝试使用逻辑而不是学习,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?

I personally find more "logical" (i.e. simple) having a fixed default initializer instead of another rule of repeating last one just for arrays. That may appear "practical" (i.e. useful) but it's IMO more logically complex.

That said however I think you're making a big mistake in trying to apply logic to a language like C++.

C++ is a complex language whose rules are the result of a long evolution history, and its current form is the result of the work of many people and even of formal committees (the last part alone could explain anything).

A language like C++ cannot be inferred by logic, it must be studied like history. Unless you're Hari Seldon there's really no way you can infer history using logical reasoning.

There are places of C++ where you're going to suffer a lot if you try to use logic instead of studying. Just to name a few...

  • Why is default dispatch static (i.e. wrong)?
  • Why there's no keyword for the null pointer?
  • Why the difference of two unsigned is unsigned?
  • Why a sum between a signed and an unsigned is unsigned?
  • If unsigned means "element of Z_{2^n}" then why sizes are unsigned?
  • Why std::string s; s=3.141592654; is perfectly valid C++?
  • Why in C++0X i = i++ + 1; is undefined behavior and i = ++i + 1; is valid?
  • Why double x=3.14; int y(int(x)); doesn't mean y will be 3?
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文