【问题标题】:Why does GCC define unary operator '&&' instead of just using '&'?为什么 GCC 定义一元运算符 '&&' 而不是仅仅使用 '&'?
【发布时间】:2015-07-06 23:01:21
【问题描述】:

正如this question 中所讨论的,GCC 定义了非标准一元运算符&& 来获取标签的地址。

为什么它定义一个新的运算符,而不是使用& 运算符的现有语义和/或函数的语义(其中foo&foo 都产生函数foo() 的地址)?

【问题讨论】:

标签: c gcc unary-operator addressof


【解决方案1】:

标签名称不会干扰其他标识符,因为它们仅在 goto 中使用。变量和标签可以具有相同的名称,并且在标准 C 和 C++ 中,从上下文中总是可以清楚地了解其含义。所以这是完全有效的:

name:
  int name;
  name = 4; // refers to the variable
  goto name; // refers to the label

因此需要区分 & 和 && 以便编译器知道期望什么样的名称:

  &name; // refers to the variable
  &&name; // refers to the label

【讨论】:

  • 嗨。如果你能澄清一下Label names live in a completely separate namespace from other identifiers..我会很感激的。我以为namespace 存在于C++ :-)
  • 删除了对“命名空间”的混淆引用。该标准使用“名称空间”。这与 C++ 命名空间特性无关。这只是意味着名称不会干扰。
【解决方案2】:

GCC 添加了这个extension 用于初始化将用作跳转表的静态数组:

static void *array[] = { &&foo, &&bar, &&hack };  

其中foobarhack 是标签。然后可以通过索引选择标签,如下所示:

goto *array[i];   

标准是这样说的

C11:6.2.1 标识符范围(p1):

一个标识符可以表示一个对象;一个函数;结构、联合或枚举的标签或成员;类型定义名称; 标签名称;宏名;或宏参数。

在第 6.2.3 节中进一步说明:

如果一个特定标识符的多个声明在翻译单元中的任何位置可见,则句法上下文消除了引用不同实体的用法的歧义。因此,不同类别的标识符有单独的名称空间,如下所示

标签名称(通过标签声明和使用的语法消除歧义);

——结构、联合和枚举的标签(通过关键字structunionenum 中的任意32 个来消除歧义) ;

——结构或联合的成员;每个结构或联合对其成员都有一个单独的名称空间(通过用于通过.-> 运算符访问成员的表达式的类型来消除歧义);

——所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量声明)。

这意味着一个对象和一个标签可以用相同的标识符表示。此时,为了让编译器知道foo的地址是标签的地址,而不是对象的地址foo(如果存在),GCC为标签地址定义了&&运算符。

【讨论】:

  • 虽然很好地回忆起我使用 Z80 的时光,但我怀疑这对 C 来说是一个好主意——尤其是当使用 switch (GCC特别提出这个替代方案)或函数指针数组(我刚刚组成)。甚至 GCC 都说“除非你真的需要,否则不要使用它”,而且很难想到一个人 真正需要的情况!学习很有趣,但实际上,充其量不过是。
  • @underscore_d:我认为这个功能可以追溯到维护者 gcc 为现代 CPU 疯狂追求积极优化之前的日子,而是试图为程序员提供工具,让他们可以用来为更简单的 CPU 生成高效代码在性能很重要的情况下。我可以很容易地想象这样的情况:直接对数组中的地址执行“goto”可以使应用程序实现优于 10% 整体的性能增益(部分增益为 20%)程序花费一半时间的代码)。
猜你喜欢
  • 2012-03-16
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多