逗号运算符 , 的作用是什么?

发布于 2024-07-04 14:18:09 字数 36 浏览 8 评论 0原文

, 运算符在 C 中起什么作用?

What does the , operator do in C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

只有一腔孤勇 2024-07-11 14:18:09

另一种用途(对已经提到的用途的补充)是一种避免单行 if 中出现大括号的方法。

// this:
if (anything) A = 1, B = 2;

// or:
if (anything)
  A = 1, B = 2;


// instead of:
if (anything) { A = 1; B = 2; }

// or:
if (anything) {
  A = 1; B = 2;
}

Another use - complementary to the already mentioned - is a method to avoid braces in a single line if.

// this:
if (anything) A = 1, B = 2;

// or:
if (anything)
  A = 1, B = 2;


// instead of:
if (anything) { A = 1; B = 2; }

// or:
if (anything) {
  A = 1; B = 2;
}
冰葑 2024-07-11 14:18:09

我恢复这个只是为了解决@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

The i case is returned as所述的大多数答案。 所有表达式都按从左到右的顺序进行计算,但只有最后一个被分配给 i( 表达式 )的结果是1`。

j 情况遵循不同的优先级规则,因为 , 具有最低的运算符优先级。 由于这些规则,编译器会看到赋值表达式、常量、常量...。 表达式再次按从左到右的顺序进行计算,并且其副作用仍然可见,因此,由于 j = 5<,j5 /代码>。

有趣的是,语言规范不允许 int j = 5,4,3,2,1;初始化程序需要一个赋值表达式,因此不允许直接使用,运算符。

希望这可以帮助。

I'm reviving this simply to address questions from @Rajesh and @JeffMercado which i think are very important since this is one of the top search engine hits.

Take the following snippet of code for example

int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);

It will print

1 5

The i case is handled as explained by most answers. All expressions are evaluated in left-to-right order but only the last one is assigned to i. The result of the ( expression )is1`.

The j case follows different precedence rules since , has the lowest operator precedence. Because of those rules, the compiler sees assignment-expression, constant, constant .... The expressions are again evaluated in left-to-right order and their side-effects stay visible, therefore, j is 5 as a result of j = 5.

Interstingly, int j = 5,4,3,2,1; is not allowed by the language spec. An initializer expects an assignment-expression so a direct , operator is not allowed.

Hope this helps.

别靠近我心 2024-07-11 14:18:09

我发现它唯一有用的地方是当您编写一个时髦的循环时,您想要在其中一个表达式(可能是 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 和循环上的多个表达式会更明显(并且我会内联初始化 i1 和 i2 而不是声明然后初始化......等等等等。)

The only place I've seen it being useful is when you write a funky loop where you want to do multiple things in one of the expressions (probably the init expression or loop expression. Something like:

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;
}

Pardon me if there are any syntax errors or if I mixed in anything that's not strict C. I'm not arguing that the , operator is good form, but that's what you could use it for. In the case above I'd probably use a while loop instead so the multiple expressions on init and loop would be more obvious. (And I'd initialize i1 and i2 inline instead of declaring and then initializing.... blah blah blah.)

棒棒糖 2024-07-11 14:18:09

它会导致对多个语句进行评估,但仅使用最后一个语句作为结果值(我认为是右值)。

所以...

int f() { return 7; }
int g() { return 8; }

int x = (printf("assigning x"), f(), g() );

应该导致 x 设置为 8。

It causes the evaluation of multiple statements, but uses only the last one as a resulting value (rvalue, I think).

So...

int f() { return 7; }
int g() { return 8; }

int x = (printf("assigning x"), f(), g() );

should result in x being set to 8.

岁月蹉跎了容颜 2024-07-11 14:18:09

正如前面的答案所述,它会评估所有语句,但使用最后一个语句作为表达式的值。 就我个人而言,我只发现它在循环表达式中有用:

for (tmp=0, i = MAX; i > 0; i--)

As earlier answers have stated it evaluates all statements but uses the last one as the value of the expression. Personally I've only found it useful in loop expressions:

for (tmp=0, i = MAX; i > 0; i--)
总攻大人 2024-07-11 14:18:09

逗号运算符将其两侧的两个表达式合并为一个,并按从左到右的顺序对它们进行求值。 右侧的值作为整个表达式的值返回。
(expr1, expr2) 就像 { expr1; 表达式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));

值是 shortint 我们这样做了:

*((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));

I'我并不是说这些例子都是好的风格! 事实上,我似乎记得 Steve McConnell 的 Code Complete 建议不要在 for 循环中使用逗号运算符:为了可读性和可维护性,循环应该仅由一个变量控制,并且 for 行本身中的表达式应该只包含循环控制代码,而不是其他额外的初始化或循环维护位。

The comma operator combines the two expressions either side of it into one, evaluating them both in left-to-right order. The value of the right-hand side is returned as the value of the whole expression.
(expr1, expr2) is like { expr1; expr2; } but you can use the result of expr2 in a function call or assignment.

It is often seen in for loops to initialise or maintain multiple variables like this:

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 */
}

Apart from this, I've only used it "in anger" in one other case, when wrapping up two operations that should always go together in a macro. We had code that copied various binary values into a byte buffer for sending on a network, and a pointer maintained where we had got up to:

unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;

*ptr++ = first_byte_value;
*ptr++ = second_byte_value;

send_buff(outbuff, (int)(ptr - outbuff));

Where the values were shorts or ints we did this:

*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;

Later we read that this was not really valid C, because (short *)ptr is no longer an l-value and can't be incremented, although our compiler at the time didn't mind. To fix this, we split the expression in two:

*(short *)ptr = short_value;
ptr += sizeof(short);

However, this approach relied on all developers remembering to put both statements in all the time. We wanted a function where you could pass in the output pointer, the value and and the value's type. This being C, not C++ with templates, we couldn't have a function take an arbitrary type, so we settled on a macro:

#define ASSIGN_INCR(p, val, type)  ((*((type) *)(p) = (val)), (p) += sizeof(type))

By using the comma operator we were able to use this in expressions or as statements as we wished:

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));

I'm not suggesting any of these examples are good style! Indeed, I seem to remember Steve McConnell's Code Complete advising against even using comma operators in a for loop: for readability and maintainability, the loop should be controlled by only one variable, and the expressions in the for line itself should only contain loop-control code, not other extra bits of initialisation or loop maintenance.

青春有你 2024-07-11 14:18:09

逗号运算符将计算左侧操作数,丢弃结果,然后计算右侧操作数,这将成为结果。 链接中指出的惯用用法是在初始化for循环中使用的变量时使用,它给出了以下示例:

void rev(char *s, size_t len)
{
  char *first;
  for ( first = s, s += len - 1; s >= first; --s)
      /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
      putchar(*s);
}

否则没有很多伟大< /em> 使用逗号运算符,尽管很容易被滥用而生成难以阅读和维护的代码。

C99 标准草案 语法如下如下:

expression:
  assignment-expression
  expression , assignment-expression

第 2 段说:

逗号运算符的左操作数被计算为空表达式;在其计算之后有一个序列点。 然后计算右操作数; 结果有其类型和值。 97) 如果尝试修改逗号运算符的结果或在下一个序列点之后访问它,则行为未定义。< /p>

脚注 97 说:

逗号运算符不会产生左值

这意味着您不能分配给逗号运算符的结果。

需要注意的是,逗号运算符具有 最低优先级,因此有使用 () 可以产生很大差异的情况,例如:

#include <stdio.h>

int main()
{
    int x, y ;

    x = 1, 2 ;
    y = (3,4) ;

    printf( "%d %d\n", x, y ) ;
}

将有以下输出:

1 4

The comma operator will evaluate the left operand, discard the result and then evaluate the right operand and that will be the result. The idiomatic use as noted in the link is when initializing the variables used in a for loop, and it gives the following example:

void rev(char *s, size_t len)
{
  char *first;
  for ( first = s, s += len - 1; s >= first; --s)
      /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
      putchar(*s);
}

Otherwise there are not many great uses of the comma operator, although it is easy to abuse to generate code that is hard to read and maintain.

From the draft C99 standard the grammar is as follows:

expression:
  assignment-expression
  expression , assignment-expression

and paragraph 2 says:

The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value. 97) If an attempt is made to modify the result of a comma operator or to access it after the next sequence point, the behavior is undefined.

Footnote 97 says:

A comma operator does not yield an lvalue.

which means you can not assign to the result of the comma operator.

It is important to note that the comma operator has the lowest precedence and therefore there are cases where using () can make a big difference, for example:

#include <stdio.h>

int main()
{
    int x, y ;

    x = 1, 2 ;
    y = (3,4) ;

    printf( "%d %d\n", x, y ) ;
}

will have the following output:

1 4
紫瑟鸿黎 2024-07-11 14:18:09

表达式:

(expression1,  expression2)

首先计算表达式1,然后计算表达式2,最后返回整个表达式的表达式2 的值。

The expression:

(expression1,  expression2)

First expression1 is evaluated, then expression2 is evaluated, and the value of expression2 is returned for the whole expression.

逆蝶 2024-07-11 14:18:09

我见过在 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);
}

I've seen used most in while loops:

string s;
while(read_string(s), s.len() > 5)
{
   //do something
}

It will do the operation, then do a test based on a side-effect. The other way would be to do it like this:

string s;
read_string(s);
while(s.len() > 5)
{
   //do something
   read_string(s);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文