首页 文章

逗号运算符是做什么的?

提问于
浏览
131

, 运算符在C中做了什么?

8 回答

  • 26

    正如之前的答案所述,它会评估所有语句,但使用最后一个语句作为表达式的值 . 我个人认为它只在循环表达式中有用:

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

    comma operator将评估左操作数,丢弃结果然后评估右操作数,这将是结果 . 链接中提到的惯用法是在初始化 for 循环中使用的变量时,它给出了以下示例:

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

    否则,逗号运算符的用法并不多,尽管生成难以阅读和维护的代码是easy to abuse .

    draft C99 standard开始,语法如下:

    expression:
      assignment-expression
      expression , assignment-expression
    

    第2段说:

    逗号运算符的左操作数被计算为void表达式;评估后有一个序列点 . 然后评估右操作数;结果有它的类型和 Value . 97)如果尝试修改逗号运算符的结果或在下一个序列点之后访问它,则行为未定义 .

    脚注97说:

    逗号运算符不会产生左值 .

    这意味着您无法分配逗号运算符的结果 .

    重要的是要注意逗号运算符具有lowest precedence,因此有些情况下使用 () 可以产生很大的不同,例如:

    #include <stdio.h>
    
    int main()
    {
        int x, y ;
    
        x = 1, 2 ;
        y = (3,4) ;
    
        printf( "%d %d\n", x, y ) ;
    }
    

    将有以下输出:

    1 4
    
  • 8

    我看到它唯一有用的地方是当你编写一个时髦的循环时,你想在其中一个表达式中做多个事情(可能是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;
    }
    

    请原谅我,如果有任何语法错误,或者我混淆了's not strict C. I' m并不认为运算符是好的形式,但's what you could use it for. In the case above I' d可能使用 while 循环,所以init和loop上的多个表达式会更明显 . (我会初始化i1和i2内联而不是声明然后初始化......等等等等 . )

  • 27

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

    逗号运算符将其两侧的两个表达式合并为一个,以从左到右的顺序对它们进行评估 . 右侧的值作为整个表达式的值返回 . (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 不再是l值而且可以't be incremented, although our compiler at the time didn' t . 为了解决这个问题,我们将表达式分为两部分:

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

    我'm not suggesting any of these examples are good style! Indeed, I seem to remember Steve McConnell'代码完成建议甚至在 for 循环中使用逗号运算符:为了可读性和可维护性,循环应该只由一个变量控制,而 for 行本身的表达式应该只包含循环控制代码,而不是其他额外的初始化或循环维护 .

  • 2

    它导致多个语句的评估,但仅使用最后一个作为结果值(我认为是rvalue) .

    所以...

    int f() { return 7; }
    int g() { return 8; }
    
    int x = (printf("assigning x"), f(), g() );
    

    应该导致x设置为8 .

  • 5

    逗号运算符没有任何意义,它是一个100%多余的功能 . 它的主要用途是“人们试图变得聪明”,因此使用它来(无意地)混淆可读代码 . 主要用途是混淆for循环,例如:

    for(int i=0, count=0; i<x; i++, count++)
    

    int i=0, count=0 实际上不是逗号运算符,而是声明列表(我们在这里已经混淆了) . i++, count++ 是逗号运算符,它首先计算左操作数,然后计算右操作数 . 逗号运算符的结果是右操作数的结果 . 左操作数的结果被丢弃 .

    但是上面的代码可以用更简单的方式编写,而不需要逗号运算符:

    int count = 0;
    for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
    {
      ...
      count++;
    }
    

    我见过的逗号运算符的唯一真正用途是关于序列点的人工讨论,因为逗号运算符带有序列点之间的序列点 . 评估左右操作数 .

    所以,如果您有一些未定义的行为代码,如下所示:

    printf("%d %d", i++, i++);
    

    实际上,您可以通过编写将其转换为仅未指定的行为(评估函数参数的顺序)

    printf("%d %d", (0,i++), (0,i++));
    

    现在在 i++ 的每个评估之间存在一个序列点,因此,即使功能参数的评估顺序仍未指定,至少程序也不会有崩溃和烧毁的风险 .

    当然没有人会在实际应用程序中编写这样的代码,它只对语言 - 律师讨论C语言中的序列点有用 .

    逗号运算符被MISRA-C:2004和MISRA-C:2012禁止,其理由是它创建的代码不太可读 .

  • 95

    表达方式:

    (expression1,  expression2)
    

    首先计算expression1,然后计算expression2,并为整个表达式返回expression2的值 .

相关问题