,
运算符在 C 语言中的作用是什么?
,
运算符在 C 语言中的作用是什么?
The expression:
(expression1, expression2)
先计算 expression1
,然后计算 expression2
,expression2
的值将作为整个表达式的返回值。
i
都不会具有值 5、4、3、2 或 1,它仅仅是 0。除非这些表达式具有副作用,否则该运算符几乎没有什么用处。 - Jeff Mercadoi = b, c;
相当于 (i = b), c
,因为赋值运算符 =
的优先级高于逗号运算符 ,
。逗号运算符的优先级最低。 - cyclaministexpression1, expression2;
中,首先计算 expression1
,可能是为了其副作用(如调用函数),然后有一个序列点,然后计算 expression2
并返回值…” - Jonathan Leffler我经常在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);
}
while (read_string(s) && s.len() > 5)
。显然,如果read_string
没有返回值(或者返回值是没有意义的),那么这种方法就行不通了。(编辑:对不起,我没有注意到这篇文章是多久以前的。) - jamesdlinwhile (1)
和break;
语句。试图强制将代码的退出部分移到while测试中或者移到do-while测试中,通常是浪费精力且使代码难以理解的做法。 - potrzebiewhile(1)
和 break
。 - Michael逗号操作符将评估左操作数,丢弃结果,然后评估右操作数,这将是结果。如链接中所述的成语用法是在初始化for
循环中使用的变量,并给出以下示例:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
expression:
assignment-expression
expression , assignment-expression
第二段落中说:
逗号运算符的左操作数被评估为void表达式;在其评估后有一个序列点。然后评估右操作数;结果具有其类型和值。
脚注97说:
逗号运算符不产生lvalue。
这意味着你不能对逗号运算符的结果进行赋值。
需要注意的是,逗号运算符具有最低优先级,因此在某些情况下使用()
可能会产生很大的差异,例如:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
将会有以下输出:
1 4
逗号运算符将其两侧的表达式合并成一个表达式,并按从左到右的顺序对它们进行评估。右侧表达式的值作为整个表达式的返回值。
(表达式1,表达式2)
就像{表达式1;表达式2;}
,但你可以在函数调用或赋值中使用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
或int
类型时,我们采用以下方法:
*((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))
通过使用逗号操作符,我们可以根据需要在表达式或语句中使用this:
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 的 《代码大全》 中甚至建议不要在 for
循环中使用逗号表达式:为了可读性和可维护性,循环应该仅由一个变量控制,而且 for
行中的表达式应该只包含循环控制代码,而不包含其他额外的初始化或循环维护部分。
这会导致多个语句被评估,但只使用最后一个作为结果值(我认为是rvalue)。
因此...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
正如之前的回答所述,它会评估所有语句,但只使用最后一个语句作为表达式的值。个人认为它只在循环表达式中有用:
for (tmp=0, i = MAX; i > 0; i--)
我认为它最有用的地方是在编写复杂循环时,你可以在表达式(通常是初始化表达式或循环表达式)中执行多个操作。例如:
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
循环,这样初始化和循环中的多个表达式会更加明显。(而且我会内联初始化i1和i2,而不是声明然后初始化....等等)
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。( 表达式 )的结果是1`。
j的情况遵循不同的优先级规则,因为,具有最低的运算符优先级。根据这些规则,编译器看到的是assignment-expression, constant, constant ...。表达式再次按从左到右的顺序进行评估,并且它们的副作用保持可见,因此,j的结果是j = 5,因此为5。
有趣的是,语言规范不允许使用int j = 5,4,3,2,1;。初始化程序期望一个assignment-expression,因此不允许直接使用,运算符。
希望这对你有所帮助。