Jer*_*emy 24 c gcc addressof unary-operator
正如在这个问题中所讨论的,GCC定义了非标准的一元运算符&&来获取标签的地址.
为什么它定义一个新的运算符,而不是使用运算符的现有语义&和/或函数的语义(where foo和&fooboth都产生函数的地址foo())?
Seb*_*edl 37
标签名称不会干扰其他标识符,因为它们仅用于gotos.变量和标签可以具有相同的名称,在标准C和C++中,它总是从上下文中清楚地表达了什么.所以这是完全有效的:
name:
int name;
name = 4; // refers to the variable
goto name; // refers to the label
Run Code Online (Sandbox Code Playgroud)
因此需要区分&和&&,以便编译器知道期望的名称类型:
&name; // refers to the variable
&&name; // refers to the label
Run Code Online (Sandbox Code Playgroud)
GCC添加了此扩展,用于初始化将用作跳转表的静态数组:
static void *array[] = { &&foo, &&bar, &&hack };
Run Code Online (Sandbox Code Playgroud)
其中foo,bar和hack是标签.然后可以使用索引选择标签,如下所示:
goto *array[i];
Run Code Online (Sandbox Code Playgroud)
标准说
标识符可以表示对象 ; 功能; 标签或结构,联合或枚举的成员; 一个typedef名称; 一个标签名称 ; 一个宏名; 或宏参数.
另外它在第6.2.3节中说:
如果在翻译单元中的任何点处可见多于一个特定标识符的声明,则句法上下文消除了引用不同实体的用法.因此,各种标识符类别都有单独的名称空间,如下所示:
- 标签名称(通过标签声明和使用的语法消除歧义);
-该标记结构,联合和枚举(由下面的任何消歧32)的关键字
struct,union或enum);- 结构或工会的成员 ; 每个结构或联合为其成员都有一个单独的名称空间(通过用于通过
.或->运算符访问成员的表达式的类型消除歧义);- 所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量).
这意味着对象和标签可以用相同的标识符表示.此时,要让编译器知道地址foo是标签的地址,而不是对象的地址foo(如果存在),GCC定义的&&运算符用于标签的地址.