C++:混淆声明语义

Posted

技术标签:

【中文标题】C++:混淆声明语义【英文标题】:C++: Confusing declaration semantics 【发布时间】:2010-11-24 21:00:21 【问题描述】:

在尝试了 Perl 和一点点 C 之后,我正在尝试学习 C++,但我已经被细节和陷阱所困扰。考虑一下:-

int x = 1;
 
  int x = x; // garbage value of x

int const arr = 3;
 
  int arr[arr]; // i am told this is perfectly valid and declares an array of 3 ints !! 
 

咦,为什么不一样?

澄清:使用同名在一种情况下有效,在另一种情况下无效。

【问题讨论】:

你能澄清你的问题吗?你指的是哪个区别? 我在尝试像 int x = x 这样简单的东西时使用相同的名称,它是无效的,我尝试对像 int arr[arr] 这样的复杂构造它是有效的。让我很困惑。 也许这很明显,但是无论上面的代码对编译器是否有意义,人类都很难理解,所以你不太可能在现有代码中看到它并且不明智地把它变成你自己的。 【参考方案1】:

欢迎来到 C++ 的世界! 对于您的问题,答案在于一个名为“声明点”的概念。

>>int x = 1;
>> int x = x;   // garbage value of x

来自章节:-3.3.1.1(C++ 标准草案) 名称的声明点紧跟在它的完整声明符之后和它的初始化器(如果有的话)之前,除非下面提到。

int x = 12;
 int x = x; 

这里; 'operator =' 是初始化器。你可以说'x'的声明点还没有达到,所以'x'的值是不确定的。

>>int const arr = 3;
>> int arr[arr];  // i am told this is perfectly valid and declares an array of 3 ints !!

为什么? 来自部分:-3.3.1.4(C++ 标准草案) 非本地名称在声明隐藏它的本地名称之前一直可见。这里的声明点是在';'特点。所以使用'arr'的早期可见值,即= 3。

此外,您可能希望知道以下内容是有效的:-

const int e = 2;
 enum  e = e ;  // enum e = 2

来自章节:-Chapter-3.3.1.4(C++ 标准草案):- 枚举数的声明点紧跟在其枚举数定义之后。

但是,不要这样做

const int Spades = 1, Clubs = 2, Hearts = 3, Diamonds = 4;
enum Suits

  Spades = Spades,     // error
  Clubs,               // error
  Hearts,              // error
  Diamonds             // error
;

为什么?因为枚举数被导出到枚举的封闭范围。在上面的示例中,声明了枚举器 Spades、Clubs、Hearts 和 Diamonds。因为枚举器被导出到封闭范围,所以它们被认为具有全局范围。示例中的标识符已经在全局范围内定义。所以这是一个错误。

有关其他详细信息和陷阱 (:-)),请阅读 C++ 标准草案中的第 3.3 节“声明性区域和范围”,如果有兴趣,可以从here(http://www.research.att.com/~bs/SC22-N-4411.pdf) 获取 pdf .

【讨论】:

谢谢你的解释,但是为什么需要这么复杂呢? 我认为“你可以说'x'的声明点还没有达到,所以'x'的值是不确定的”是错误的。声明点已经到达,这就是“x”不确定的原因,因为它已经声明了,但还没有初始化。 规则需要复杂的原因是C++声明符复杂的。那里有很多功能,再加上很多向后兼容的问题,没有从它的 C 历史中彻底中断(这些东西没有像这样正式地指定,并且像这样的边缘情况通常取决于编译器实现者),而且你获取 C++ 标准规则。 @Gorpik:在我读到“除了下文所述”之前,我也是这么想的。该示例直接来自标准。我相信这意味着没有达到声明点。也许 Neil、litb 等可以澄清一下。 @unknown(获取正确的用户帐户!):阅读 Stroustrup 的 D&EC++ research.att.com/~bs/dne.html - 即使它没有回答您的具体问题,它也会让您了解权衡取舍的方式参与设计C++。这是向 C 添加新功能和保留现有样式之间的折衷。局部变量在 C 中隐藏全局变量。(在 C# 中,他们采用了不同的方法,使得无法在嵌套的局部范围内重新声明名称,这非常好,因为大多数人都试图避免隐藏名称。)【参考方案2】:

首先,在现实世界中你不应该使用这两者,因为它是令人困惑的,即使是几秒钟来理解这一点也太浪费了。

放弃我的其余答案 - Abhay 已经说对了,而且更详细:)

【讨论】:

虽然不是这个问题的真正答案,但它得到了实用主义的支持。 +1 我也同意你的实用主义:-)。但我想作为学习者的 O.P. 对陷阱的性质感到惊讶。

以上是关于C++:混淆声明语义的主要内容,如果未能解决你的问题,请参考以下文章

语义分割评价指标(Dice coefficient, IoU)

C++ 中的值语义技巧

[论文阅读] (17)CCS2019 针对PowerShell脚本的轻量级去混淆和语义感知攻击检测(经典)

语义分割⚠️偷偷惊呆所有人 1⚠️ 语义分割简介

c++ 移动语义及使用(续)

c++的三种变量语义