【问题标题】:Nuances of comma seperator and comma operator when used in initialization and declaration statements在初始化和声明语句中使用逗号分隔符和逗号运算符时的细微差别
【发布时间】:2020-12-29 06:55:22
【问题描述】:

在阅读了 Stack Overflow 帖子 (What does the comma operator , do?) 上的几个答案后,我在玩 , operator。此外,在阅读了这篇文章后,我正在使用, 分隔符comma operator and comma seperator in c++。考虑以下两个代码 sn-ps:

代码 1

#include<stdio.h>
int main(void) 
{
  int a, b;      /* comma functions as a separator */
  a = 5, b=9;    /* NOT SURE how comma functions */
  printf("a = %d \n",a) , printf("b = %d \n",b);     /* comma functions as an operator */      
}

代码 2

#include<stdio.h>
int main(void) 
{
  int a, int b;   /* not allowed - compiler error ... NOT SURE how comma functions */
  a = 5, b=9;     /*NOT SURE how comma functions */
  printf("a = %d \n",a) , printf("b = %d \n",b);      /*comma functions as an operator */      
}

顶部代码(代码 1)很好...并打印出 a=5b=9;但是,底部代码(代码 2)没有通过编译器并引用 int a, int b ; 行作为有罪的行为。


这两个代码 sn-ps 中包含了很多问题,但我会列出我最关心的问题:

  1. 在语句a=5,b=9; 中,, 是作为分隔符还是运算符?我在初始化语句中读到过,逗号用作分隔符。但是,鉴于我对逗号运算符的作用的理解,我觉得将此逗号归类为运算符也是有道理的。

  2. 为什么不允许int a, int b?如果允许逗号充当运算符,那么这肯定是有道理的,对吧? int a 将首先被评估,它会产生用a 标识符标记内存中某个位置的副作用,然后int b 将以类似的方式处理。因此,似乎编译器在这种情况下不想改变, 的解释(即它只想将其视为分隔符)。

非常感谢您的解释!谢谢~

【问题讨论】:

  • 1) 是一个运算符,a=5,b=9;是一个完整的表达式,返回值9。 2) int a 将首先被评估 - int a 不是要评估的表达式,它是一个定义。所以在它周围放置运算符是没有意义的。
  • @EugeneSh 您能否详细说明一下您所说的“不是要评估的表达式”是什么意思?我不确定我是否理解。语句“int a;”在编译时正在“评估”,对吧?
  • port70.net/~nsz/c/c11/n1570.html#6.5 - 第 6.5 节 - 表达式
  • @EugeneSh 啊。很棒的链接。谢谢!因此,为了澄清起见,“int a”不是表达式,因为它不包含运算符。是吗?

标签: c declaration comma comma-operator


【解决方案1】:
  1. a=5,b=9; 语句中的 , 是用作分隔符还是运算符?

它是一个运算符。

我在初始化语句中读过,逗号 起到分隔符的作用。但是,鉴于我对什么是 逗号运算符会做,我想将此逗号归类为 运算符也很有意义。

没有“初始化语句”这样的东西。初始化,在您一定已经阅读过的意义上,是可以表示为对象的声明的一部分的东西。 赋值,即使是对未初始化变量的第一次赋值,在这个意义上也不是初始化。尽管语法相似。

  1. 为什么不允许int a, int b

最终,因为语言设计者认为不应该这样做。不过……

如果允许逗号充当运算符,那么这肯定是有道理的,对吧?

不,不是特别。要使, 在那里充当运算符,int aint b 需要是表达式,作为其操作数。他们不是。相反,它们都是声明。区别之一是声明不评估为值。

int a 将首先被评估,它会产生副作用 用a标识符标记内存中的某个位置,然后int b将以类似的方式处理。

也许在其他语言中它可以这样工作。在 C 中,它没有。

因此,似乎 编译器不想改变, 的解释 这种情况(即它只想将其视为分隔符)。

逗号分隔符是用于声明的 C 语法的一部分(除其他外)。逗号作为运算符是表达式的 C 语法的一部分。如果它让你感到困惑或者你不喜欢它,那么你可以避免在声明中使用逗号作为分隔符:相反,写

int a;
int b;

事实上,一些 C 风格指南要求不要在同一语句中声明多个变量。

【讨论】:

  • 关于“赋值,即使是对未初始化变量的第一次赋值,也不是初始化”:这是为了 C 标准的目的。 C 2018 6.3.2.1 2 中的规则取决于此;如果一个对象通过定义中的初始化或赋值给了一个值,则它不是未初始化的。 C标准规定对象可以在其定义中进行初始化,但并没有说这是“初始化”的唯一含义;任何赋予对象第一个值的赋值都是初始化。
  • @EricPostpischil,该标准在使用该词的方式上有点快和松散。人们可能更愿意使用第 6.7.9 节“初始化”来定义该术语的一般含义。或者,人们可能会通过断言即使标准说已分配值的对象不是未初始化的,也不会使任何分配成为“初始化”来分裂头发。然而,将这些留到另一天,我只是更新了这个答案,以指定我指的是初始化,因为 OP 的文本必须意味着该术语。
【解决方案2】:

C 中的声明是这样定义的(特别是)

declaration:
    declaration-specifiers init-declarator-list ; 

init-declarator-list 定义如下

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator

所以在这个声明的第一个程序中

int a, b;

没有逗号运算符。逗号用于分隔init-declarator-list 中的init-declarators

此声明

a = 5, b=9; 

确实是带有逗号运算符表达式的语句。

此声明

printf("a = %d \n",a) , printf("b = %d \n",b);

也是带有逗号运算符表达式的语句。

第二个程序中的这个声明不正确

int a, int b; 

因为init-declarator-list.内部使用了声明说明符int

至于逗号运算符则根据 C 标准(6.5.17 逗号运算符)

2 逗号运算符的左操作数被评估为 void 表达;在它的评估和那个之间有一个序列点 的右操作数。然后评估右操作数;结果 有它的类型和价值

您可以使用逗号运算符作为变量的初始化器,例如

int a = 10, b = 20;
int c = ( a++, b++, a + b );

变量c将由值32初始化。

这是一个演示程序。

#include <stdio.h>

int main(void) 
{
    int a = 10, b = 20;
    
    printf( "a = %d, b = %d\n", a, b );
    
    int c = ( a++, b++, a + b );

    printf( "a = %d, b = %d, c = %d\n", a, b, c );

    return 0;
}

它的输出是

a = 10, b = 20
a = 11, b = 21, c = 32

【讨论】:

    【解决方案3】:
    1. 在语句a=5,b=9;那是作为分隔符还是运算符?

    这里的逗号是一个运算符。在C语法中:

    • 这是一个 statement,它是一个 expression-statement (C 2018 6.8)。
    • 它由一个表达式和一个; (6.8.3)组成。
    • 表达式可以是一个表达式,后跟一个,,然后是一个assignment-expression (6.5.17)。李>
    • 逗号前的表达式也可能是赋值表达式 (6.5.17)。

    所以a=5,b=9; 是“assignment-expression , assignment-expression ;”。

    请注意,a=5 不是“初始化语句”; C语法中没有这样的东西。它是一个赋值表达式。所以a=5,b=9; 是两个用逗号连接并以分号结尾的赋值表达式,形成一条语句。

    1. 为什么不允许int a、int b?

    在C语法中:

    • 这是一个声明 (6.7)。
    • 它由 declaration-specifiers 后跟 init-declarator-list 后跟 ; (6.7) 组成。
    • 声明说明符可以是单个类型说明符 (6.7),即int (6.7.2)。
    • init-declarator-list 是由逗号分隔的 init-declarator 列表 (6.7)。
    • init-declarator 可能是 declarator (6.7)。
    • declarator 可以是标识符,例如 ab (6.7.6)。

    所以int a, b; 是一个有效的声明。 C 语法中没有规定任何由逗号分隔的声明列表;语法中的任何内容都不允许任何内容扩展为“declarationdeclaration”。

    int a, b; 中,我们可以有一个用逗号分隔的标识符列表,因为init-declarator-list 的语法允许这样做。

    (init-declarator-list 中的 init-declarator 项也可以是“declarator = initializer”,这是您可以在声明中进行初始化的方式。)

    【讨论】:

      猜你喜欢
      • 2017-01-18
      • 1970-01-01
      • 2014-08-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 2019-06-09
      • 2019-08-19
      • 1970-01-01
      相关资源
      最近更新 更多