,
运算符在 C 中做什么?
8 回答
表达方式:
(expression1, expression2)
首先计算表达式 1,然后计算表达式 2,并为整个表达式返回表达式 2 的值。
我见过在while
循环中使用最多:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
它将执行操作,然后根据副作用进行测试。另一种方法是这样做:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
逗号运算符将评估左操作数,丢弃结果,然后评估右操作数,这将是结果。链接中提到的惯用用法是在初始化for
循环中使用的变量时,它给出了以下示例:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
否则,逗号运算符的用途并不多,尽管它很容易被滥用来生成难以阅读和维护的代码。
从C99 标准草案中,语法如下:
expression:
assignment-expression
expression , assignment-expression
第2段说:
逗号运算符的左操作数被评估为 void 表达式;在其评估之后有一个序列点。然后对右操作数求值;结果有它的类型和值。 97)如果尝试修改逗号运算符的结果或在下一个序列点之后访问它,则行为未定义。
脚注 97说:
逗号运算符不会产生左值。
这意味着您不能分配给逗号运算符的结果。
重要的是要注意逗号运算符的优先级最低,因此在某些情况下 using()
可以产生很大的不同,例如:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
将有以下输出:
1 4
逗号运算符将其两侧的两个表达式组合为一个,以从左到右的顺序对它们进行计算。右侧的值作为整个表达式的值返回。
(expr1, expr2)
就像{ expr1; expr2; }
但你可以expr2
在函数调用或赋值中使用结果。
在for
循环中经常看到初始化或维护多个变量,如下所示:
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
除此之外,我只在另一种情况下“愤怒地”使用它,当包装两个应该始终在宏中一起使用的操作时。我们有将各种二进制值复制到字节缓冲区中以便在网络上发送的代码,并在我们已经到达的位置维护了一个指针:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
在值是short
s 或int
s 的地方,我们这样做了:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
后来我们读到这不是真正有效的 C,因为(short *)ptr
不再是左值并且不能递增,尽管我们当时的编译器并不介意。为了解决这个问题,我们将表达式一分为二:
*(short *)ptr = short_value;
ptr += sizeof(short);
但是,这种方法依赖于所有开发人员记住始终将这两个语句都放入。我们想要一个函数,您可以在其中传递输出指针、值和值的类型。这是 C,而不是带有模板的 C++,我们不能让函数采用任意类型,所以我们选择了一个宏:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
通过使用逗号运算符,我们可以在表达式中使用它,或者按照我们的意愿作为语句使用它:
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
我并不是说这些例子中的任何一个都是好的风格!事实上,我似乎记得 Steve McConnell 的Code Complete建议不要在循环中使用逗号运算符for
:为了可读性和可维护性,循环应该只由一个变量控制,并且for
行本身的表达式应该只包含循环控制代码,不是其他额外的初始化或循环维护。
它会导致对多个语句的评估,但仅使用最后一个作为结果值(我认为是右值)。
所以...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
应该导致 x 设置为 8。
正如之前的答案所述,它评估所有语句,但使用最后一个作为表达式的值。就我个人而言,我只发现它在循环表达式中有用:
for (tmp=0, i = MAX; i > 0; i--)
我看到它有用的唯一地方是当您编写一个时髦的循环时,您想在其中一个表达式中执行多项操作(可能是 init 表达式或循环表达式。类似于:
bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
size_t i1, i2;
for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
{
if(a1[i1] != a2[i2])
{
return false;
}
}
return true;
}
如果有任何语法错误或者我混合了任何不严格的 C 语言,请原谅我。我并不是说 , 运算符是好的形式,但这就是您可以使用它的目的。在上述情况下,我可能会改用while
循环,因此 init 和 loop 上的多个表达式会更明显。(而且我会内联初始化 i1 和 i2,而不是先声明然后初始化......等等等等。)
我恢复这个只是为了解决来自@Rajesh 和@JeffMercado 的问题,我认为这些问题非常重要,因为这是搜索引擎的热门搜索之一。
以下面的代码片段为例
int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);
它会打印
1 5
该i
案例的处理方式如大多数答案所解释。所有表达式都按从左到右的顺序计算,但只有最后一个分配给i
. (
表达式) is
1`的结果。
该j
案例遵循不同的优先级规则,因为,
具有最低的运算符优先级。由于这些规则,编译器会看到assignment-expression, constant, constant ...。表达式再次以从左到右的顺序进行评估,并且它们的副作用保持可见,因此,j
是.5
j = 5
有趣的int j = 5,4,3,2,1;
是,语言规范不允许。初始化程序需要一个赋值表达式,
,因此不允许使用直接运算符。
希望这可以帮助。