为什么GCC定义一元运算符'&'而不是仅仅使用'&'?

时间:2021-08-31 22:29:29

As discussed in this question, GCC defines nonstandard unary operator && to take the address of a label.

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

Why does it define a new operator, instead of using the existing semantics of the & operator, and/or the semantics of functions (where foo and &foo both yield the address of the function foo())?

为什么它定义一个新的操作符,而不是使用&操作符的现有语义和/或函数的语义(foo和&foo都给出函数foo()的地址)?

2 个解决方案

#1


37  

Label names do not interfere with other identifiers, because they are only used in gotos. A variable and a label can have the same name, and in standard C and C++ it's always clear from the context what is meant. So this is perfectly valid:

标签名称不会干扰其他标识符,因为它们只在goto中使用。一个变量和一个标签可以有相同的名称,在标准C和c++中,它总是从上下文中清楚地知道什么是含义。这是完全正确的

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

The distinction between & and && is thus needed so the compiler knows what kind of name to expect:

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

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

#2


9  

GCC added this extension to be used in initializing a static array that will serve as a jump table:

GCC增加了这个扩展,用于初始化将作为跳转表的静态数组:

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

Where foo, bar and hack are labels. Then a label can be selected with indexing, like this:

其中foo、bar和hack是标签。然后可以通过索引选择一个标签,如下所示:

goto *array[i];   

Standard says that

标准说

C11: 6.2.1 Scopes of identifiers (p1):

An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter.

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

Further it says in section 6.2.3:

此外,它在第6.2.3节中说:

If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:

如果在翻译单元的任何位置都可以看到一个特定标识符的多个声明,那么语法上下文将消除对引用不同实体的使用的歧义。因此,对于不同类别的标识符有单独的名称空间,如下所示:

label names (disambiguated by the syntax of the label declaration and use);

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

— the tags of structures, unions, and enumerations (disambiguated by following any32) of the keywords struct, union, or enum);

-关键字struct、union或enum的结构、联合和枚举的标记(在any32之后消除歧义);

— the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);

-结构或工会成员;每个结构或联合都有一个单独的成员名称空间(通过用于访问成员的表达式的类型消除歧义)。或- >操作符);

— all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).

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

This means that an object and a label can be denoted by same identifier. At this point, to let the compiler know that the address of foo is the address of a label, not the address of an object foo (if exists), GCC defined && operator for address of label.

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

#1


37  

Label names do not interfere with other identifiers, because they are only used in gotos. A variable and a label can have the same name, and in standard C and C++ it's always clear from the context what is meant. So this is perfectly valid:

标签名称不会干扰其他标识符,因为它们只在goto中使用。一个变量和一个标签可以有相同的名称,在标准C和c++中,它总是从上下文中清楚地知道什么是含义。这是完全正确的

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

The distinction between & and && is thus needed so the compiler knows what kind of name to expect:

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

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

#2


9  

GCC added this extension to be used in initializing a static array that will serve as a jump table:

GCC增加了这个扩展,用于初始化将作为跳转表的静态数组:

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

Where foo, bar and hack are labels. Then a label can be selected with indexing, like this:

其中foo、bar和hack是标签。然后可以通过索引选择一个标签,如下所示:

goto *array[i];   

Standard says that

标准说

C11: 6.2.1 Scopes of identifiers (p1):

An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter.

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

Further it says in section 6.2.3:

此外,它在第6.2.3节中说:

If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:

如果在翻译单元的任何位置都可以看到一个特定标识符的多个声明,那么语法上下文将消除对引用不同实体的使用的歧义。因此,对于不同类别的标识符有单独的名称空间,如下所示:

label names (disambiguated by the syntax of the label declaration and use);

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

— the tags of structures, unions, and enumerations (disambiguated by following any32) of the keywords struct, union, or enum);

-关键字struct、union或enum的结构、联合和枚举的标记(在any32之后消除歧义);

— the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);

-结构或工会成员;每个结构或联合都有一个单独的成员名称空间(通过用于访问成员的表达式的类型消除歧义)。或- >操作符);

— all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).

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

This means that an object and a label can be denoted by same identifier. At this point, to let the compiler know that the address of foo is the address of a label, not the address of an object foo (if exists), GCC defined && operator for address of label.

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