24

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

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

4

2 回答 2

38

标签名称不会干扰其他标识符,因为它们仅在 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
于 2015-04-28T07:59:31.407 回答
9

GCC 添加了这个扩展来初始化一个用作跳转表的静态数组:

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

其中foo和是bar标签hack。然后可以使用索引选择标签,如下所示:

goto *array[i];   

标准说

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

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

此外,它在第 6.2.3 节中说:

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

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

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

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

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

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

于 2015-04-28T11:02:00.537 回答