正如this question中所讨论的,GCC定义了非标准一元运算符&&
来获取标签的地址。
为什么它定义一个新的运算符,而不是使用&
运算符的现有语义和/或函数的语义(其中foo
和&foo
都产生地址函数foo()
)?
答案 0 :(得分:37)
标签名称不会干扰其他标识符,因为它们仅用于gotos。变量和标签可以具有相同的名称,并且在标准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
答案 1 :(得分:9)
GCC添加了此extension用于初始化将用作跳转表的静态数组:
static void *array[] = { &&foo, &&bar, &&hack };
foo
,bar
和hack
是标签。然后可以使用索引选择标签,如下所示:
goto *array[i];
标准说
标识符可以表示对象;功能;标签或结构,联合或枚举的成员;一个typedef名称; 标签名称;一个宏名;或宏参数。
此外,它在第6.2.3节中说:
如果在翻译单元中的任何一点可以看到多个特定标识符的声明,则语法上下文消除了引用不同实体的用法。因此,对于各种类别的标识符,存在单独的名称空间,如下所示:
- 标签名称 (通过标签声明和使用的语法消除歧义);
- 结构,联合和枚举的标记(通过遵循任何 32消除歧义)关键字
struct
,union
或enum
);- 结构或工会的成员;每个结构或联合为其成员都有一个单独的名称空间(通过
.
或->
运算符用于访问成员的表达式的类型消除歧义;- 所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量)。
这意味着对象和标签可以用相同的标识符表示。此时,为了让编译器知道foo
的地址是标签的地址,而不是对象foo
的地址(如果存在),GCC定义了&&
运算符标签地址。