当 C 中没有左侧时,&& 运算符会做什么?
What does a && operator do when there is no left side in C?
我看到一个 C 语言的程序,其代码如下:
static void *arr[1] = {&& varOne,&& varTwo,&& varThree};
varOne: printf("One") ;
varTwo: printf("Two") ;
varThree: printf("Three") ;
我对 &&
的作用感到困惑,因为它左边什么也没有。它默认评估为 null 吗?或者这是特例?
编辑:
添加了更多信息以使 question/code 对我的问题更加清晰。
谢谢大家的帮助。这是 gcc 特定扩展的一个例子。
我不知道有任何运算符在 C 中以这种方式工作。
根据上下文的不同,C 中的 & 符号可以表示许多不同的意思。
地址运算符
在左值之前,例如
int j;
int* ptr = &j;
在上面的代码中,ptr 存储 j 的地址,& 在这种情况下是获取任何左值的地址。下面的代码,如果是这样写的,对我来说会更有意义。
static int varOne;
static int varTwo;
static int varThree;
static void *arr[1][8432] = { { &varOne,&varTwo, &varThree } };
逻辑与
逻辑与运算符更简单,与上面的运算符不同,它是一个二元运算符,这意味着它需要一个左右操作数。它的工作方式是评估左右操作数并返回 true,当且仅当两者都为真,或者如果它们不是 bool,则返回大于 0。
bool flag = true;
bool flag2 = false;
if (flag && flag2) {
// Not evaluated
}
flag2 = true;
if (flag && flag2) {
// Evaluated
}
按位与
C 中符号的另一种用法是执行按位与。它类似于逻辑与运算符,只是它只使用一个符号,并在位级别执行与运算。
假设我们有一个数字并且它映射到如下所示的二进制表示,AND 运算如下所示:
0 0 0 0 0 0 1 0
1 0 0 1 0 1 1 0
---------------
0 0 0 0 0 0 1 0
在 C++ 领域,事情变得更加复杂。 &符号可以放在类型之后以表示引用类型(您可以将其视为一种功能较弱但安全的指针),然后当两个&符号放在后面时,事情变得更加复杂 1) 右值引用一种。 2) 模板类型或自动扣除类型后放置两个&符号时的通用引用。
我认为由于某种扩展,您的代码可能只能在您的编译器中编译。我正在考虑这个 https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C 但我怀疑情况是否如此。
它是一个特定于 gcc 的扩展,一个一元 &&
运算符,可以应用于标签名称,产生其地址作为 void*
值。
作为扩展的一部分,允许 goto *ptr;
,其中 ptr
是 void*
.
类型的表达式
在 gcc 手册中有记载here。
You can get the address of a label defined in the current function (or
a containing function) with the unary operator &&
. The value has
type void *
. This value is a constant and can be used wherever a
constant of that type is valid. For example:
void *ptr;
/* ... */
ptr = &&foo;
To use these values, you need to be able to jump to one. This is done
with the computed goto statement, goto *exp;
. For example,
goto *ptr;
Any expression of type void *
is allowed.
正如 zwol 在评论中指出的那样,gcc 使用 &&
而不是更明显的 &
因为标签和具有相同名称的对象可以同时可见,使得 &foo
如果 &
表示 "address of label",则可能存在歧义。标签名称占据它们自己的名称空间(不是 C++ 意义上的),并且只能出现在特定的上下文中:由 labeled-statement 定义,作为 goto
语句的目标,或者,对于 gcc,作为一元 &&
.
的操作数
这是一个 gcc 扩展,称为 "Labels as Values"。 Link to gcc documentation.
在此扩展中,&&
是可应用于 标签的一元运算符。结果是 void *
类型的值。此值稍后可能会在 goto
语句中取消引用,以导致执行跳转到该标签。此外,允许对该值进行指针运算。
标签必须在同一个函数中;或者在封闭函数中,以防代码也使用 "nested functions".
的 gcc 扩展
这是一个示例程序,其中该功能用于实现状态机:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
void *tab[] = { &&foo, &&bar, &&qux };
// Alternative method
//ptrdiff_t otab[] = { &&foo - &&foo, &&bar - &&foo, &&qux - &&foo };
int i, state = 0;
srand(time(NULL));
for (i = 0; i < 10; ++i)
{
goto *tab[state];
//goto *(&&foo + otab[state]);
foo:
printf("Foo\n");
state = 2;
continue;
bar:
printf("Bar\n");
state = 0;
continue;
qux:
printf("Qux\n");
state = rand() % 3;
continue;
}
}
编译执行:
$ gcc -o x x.c && ./x
Foo
Qux
Foo
Qux
Bar
Foo
Qux
Qux
Bar
Foo
我看到一个 C 语言的程序,其代码如下:
static void *arr[1] = {&& varOne,&& varTwo,&& varThree};
varOne: printf("One") ;
varTwo: printf("Two") ;
varThree: printf("Three") ;
我对 &&
的作用感到困惑,因为它左边什么也没有。它默认评估为 null 吗?或者这是特例?
编辑: 添加了更多信息以使 question/code 对我的问题更加清晰。 谢谢大家的帮助。这是 gcc 特定扩展的一个例子。
我不知道有任何运算符在 C 中以这种方式工作。 根据上下文的不同,C 中的 & 符号可以表示许多不同的意思。
地址运算符
在左值之前,例如
int j;
int* ptr = &j;
在上面的代码中,ptr 存储 j 的地址,& 在这种情况下是获取任何左值的地址。下面的代码,如果是这样写的,对我来说会更有意义。
static int varOne;
static int varTwo;
static int varThree;
static void *arr[1][8432] = { { &varOne,&varTwo, &varThree } };
逻辑与
逻辑与运算符更简单,与上面的运算符不同,它是一个二元运算符,这意味着它需要一个左右操作数。它的工作方式是评估左右操作数并返回 true,当且仅当两者都为真,或者如果它们不是 bool,则返回大于 0。
bool flag = true;
bool flag2 = false;
if (flag && flag2) {
// Not evaluated
}
flag2 = true;
if (flag && flag2) {
// Evaluated
}
按位与
C 中符号的另一种用法是执行按位与。它类似于逻辑与运算符,只是它只使用一个符号,并在位级别执行与运算。
假设我们有一个数字并且它映射到如下所示的二进制表示,AND 运算如下所示:
0 0 0 0 0 0 1 0
1 0 0 1 0 1 1 0
---------------
0 0 0 0 0 0 1 0
在 C++ 领域,事情变得更加复杂。 &符号可以放在类型之后以表示引用类型(您可以将其视为一种功能较弱但安全的指针),然后当两个&符号放在后面时,事情变得更加复杂 1) 右值引用一种。 2) 模板类型或自动扣除类型后放置两个&符号时的通用引用。
我认为由于某种扩展,您的代码可能只能在您的编译器中编译。我正在考虑这个 https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C 但我怀疑情况是否如此。
它是一个特定于 gcc 的扩展,一个一元 &&
运算符,可以应用于标签名称,产生其地址作为 void*
值。
作为扩展的一部分,允许 goto *ptr;
,其中 ptr
是 void*
.
在 gcc 手册中有记载here。
You can get the address of a label defined in the current function (or a containing function) with the unary operator
&&
. The value has typevoid *
. This value is a constant and can be used wherever a constant of that type is valid. For example:void *ptr; /* ... */ ptr = &&foo;
To use these values, you need to be able to jump to one. This is done with the computed goto statement,
goto *exp;
. For example,goto *ptr;
Any expression of type
void *
is allowed.
正如 zwol 在评论中指出的那样,gcc 使用 &&
而不是更明显的 &
因为标签和具有相同名称的对象可以同时可见,使得 &foo
如果 &
表示 "address of label",则可能存在歧义。标签名称占据它们自己的名称空间(不是 C++ 意义上的),并且只能出现在特定的上下文中:由 labeled-statement 定义,作为 goto
语句的目标,或者,对于 gcc,作为一元 &&
.
这是一个 gcc 扩展,称为 "Labels as Values"。 Link to gcc documentation.
在此扩展中,&&
是可应用于 标签的一元运算符。结果是 void *
类型的值。此值稍后可能会在 goto
语句中取消引用,以导致执行跳转到该标签。此外,允许对该值进行指针运算。
标签必须在同一个函数中;或者在封闭函数中,以防代码也使用 "nested functions".
的 gcc 扩展这是一个示例程序,其中该功能用于实现状态机:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
void *tab[] = { &&foo, &&bar, &&qux };
// Alternative method
//ptrdiff_t otab[] = { &&foo - &&foo, &&bar - &&foo, &&qux - &&foo };
int i, state = 0;
srand(time(NULL));
for (i = 0; i < 10; ++i)
{
goto *tab[state];
//goto *(&&foo + otab[state]);
foo:
printf("Foo\n");
state = 2;
continue;
bar:
printf("Bar\n");
state = 0;
continue;
qux:
printf("Qux\n");
state = rand() % 3;
continue;
}
}
编译执行:
$ gcc -o x x.c && ./x
Foo
Qux
Foo
Qux
Bar
Foo
Qux
Qux
Bar
Foo