哪些语言标准允许在固定大小的数组中忽略空终止符?

20

我们正在将C代码转换为C++。
我注意到以下代码在C中定义良好,

int main(){

  //length is valid. '\0' is ignored
  char  str[3]="abc";
}

根据数组初始化所述:

"如果数组的大小是已知的,它可能比字符串字面量的大小小1,此时终止空字符将被忽略。"

然而,如果我在C++中构建相同的代码,我会得到以下C++错误:

error: initializer-string for array of chars is too long
[-fpermissive]    char  str[3]="abc";

我希望有人可以解释一下这个问题。

问题:
这个代码示例在所有C语言标准中都有效吗?
在所有C++语言标准中都无效吗?
是否有一个原因,使其在一种语言中有效而在另一种语言中无效?


10
你在引用所有标准。是的,这是有效的 C 代码。是的,这也是不符合 C++ 标准的代码。有什么不清楚的吗?没有人确切知道原因,但大多数人认为,总体上 C++ 比 C 更加严格。 - SergeyA
5
C和C++是不同的编程语言,所以为什么你希望它们表现相同呢?而且仅仅是将C代码在C++中运行通常是个坏主意。要么继续使用C代码作为独立模块,要么使用C++的特性/库进行重写。此外,显示的代码在C中也很糟糕,除非你不需要一个“字符串”。在那种情况下,使用初始化列表是更好的方法。 - too honest for this site
3
@Olaf GNU89也是一个标准。 - fuz
2
让我们保持评论文明,避免侮辱。我已经清理了这里的东西。 - Brad Larson
3
“那你为什么期望它们表现一致呢?”因为C++的设计考虑到了兼容性,标准委员会会在可能和适当的情况下保留兼容性。例如,C标准库是C++标准的一部分;大多数实现都使用相同的库二进制文件和头文件源代码来支持两种语言。这是一个设计特点。与此原则相悖的偏差很少,并且委员会成员通常会在事后对其表示遗憾。 - Peter - Reinstate Monica
显示剩余19条评论
2个回答

16
这里看到的是 C 和 C++ 中 cstring 的初始化规则的差异。在 C11 §6.7.9/14 中,我们可以看到:

字符类型的数组可以通过一个字符串字面值或 UTF−8 字符串字面值(可选地用花括号括起来)进行初始化。字符串字面值的连续字节(包括空字符终止符,如果有足够的空间或者数组大小未知)初始化数组的元素。

强调为本文者添加

只要数组足够大,排除空终止符,它就是有效的。因此,

char  str[3]="abc";

在C语言中,这是有效的。然而,在C++14中,控制这一行为的规则可以在[dcl.init.string]/2中找到:

初始化程序的数量不应超过数组元素的数量。

并且继续展示以下代码是错误的。

char cv[4] = "asdf"; // error

因此,在C++中,您必须有足够的存储空间来容纳整个字符串文字,包括空终止符。


@VladfromMoscow,我刚刚重新表述了C部分。这样清晰明了吗? - NathanOliver
1
可能查看C++设计理念会很有用,但我不知道在哪里找到它。 - fuz
2
@FUZxxl大概是出于安全考虑。通常你需要有空字符终止符,使其成为一个合适的C字符串。 - NathanOliver
1
我认为C++希望您将字符串视为字符串,而C一直更加灵活。 - user5940189
标准只提到空终止符以明确它也被复制,如果有足够的空间。这并不意味着“只要数组足够大,可以容纳字符串(不包括空终止符),它就是有效的”。数组的长度可以是任意的;它将从字面上初始化,只要它们中的任何一个到达即可。 - Peter - Reinstate Monica
显示剩余6条评论

5
代码示例在所有C语言标准中都有效吗?
请注意,每次只能生效一个ISO标准;C2011替代了C99,后者替代了C89。
我相信它应该在任何一个标准下都有效。
代码示例在所有C++语言标准中都无效吗?
与上面相同,只需将“有效”更改为“无效”。
在一种语言中有效但在另一种语言中无效的原因是什么?
最有可能的是,它在C中保持有效,以免破坏依赖该行为的任何传统代码。C++在大约十年后出现,试图解决一些C的缺点,而这就是其中被填补的漏洞之一。
许多现代编程语言是早期语言的迭代和改进;C是带有类型系统的B语言,C++是具有OO支持和更好的类型安全性的C语言,Java和C#是带有较少未定义行为的C++语言等。

4
Java和C++几乎没有什么共同之处,花括号是它们最重要的共同特征。 - n. m.
3
如果一个结构中有足够容量存储一个确切大小的字符串,那么允许元素被初始化为“INIT”比要求它被写成{'I','N','I','T'}更方便。最好的情况是有一种语法来显式地指示没有终止符的字符串,但是C和C++似乎都没有这样的语法。 - supercat
@n.m. 他们的语法完全相同,但不仅仅是在这里停止。 - cat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接