【问题标题】:Why can't I put a variable declaration in the test portion of a while loop?为什么我不能在 while 循环的测试部分中放置变量声明?
【发布时间】:2023-03-15 06:10:01
【问题描述】:

显然,您可以将变量声明放在 for 循环中:

for (int i = 0; ...

我注意到你也可以在 if 和 switch 语句中做同样的事情:

if ((int i = f()) != 0) ...

switch (int ch = stream.get()) ...

但是当我尝试在 while 循环中做同样的事情时:

while ((int ch = stream.get()) != -1) ...

编译器 (VC++ 9.0) 根本不喜欢它。

这是合规行为吗?有什么原因吗?

编辑:我发现我可以这样做:

while (int ch = stream.get() != -1) ...

但由于优先规则,这被解释为:

while (int ch = (stream.get() != -1)) ...

这不是我想要的。

【问题讨论】:

  • gcc 也不允许我在“if”语句中声明变量,实际上
  • 你不是说上一个例子中的 while (int ch = (stream.get() != -1)) 吗?
  • 作为解决此问题的一个选项,您可能需要考虑逗号运算符:while (int ch, (ch = stream.get()) != -1) {//do stuff here }
  • @Steve - 是的,当然。相应地进行了编辑。

标签: c++


【解决方案1】:

'03 标准中条件的语法定义如下:

condition:
  expression
  type-specifier-seq declarator = assignment-expression

因此,以上将只允许以下条件:

if ( i && j && k ) {}
if ( (i = j) ==0 ) {}
if ( int i = j ) {}

标准允许条件声明一个变量,但是,他们通过添加一个名为“条件”的新语法规则来实现这一点,该条件可以是表达式或带有初始化程序的声明符。结果是,仅仅因为您处于ifforwhileswitch 的条件并不意味着您可以在表达式中声明变量。

【讨论】:

  • 对——关键是声明不是表达式。
【解决方案2】:

问题是,标准允许您在括号内添加一个声明。您想要做的是将声明作为表达式的一部分,这是标准不允许您这样做的。

while() 可以具有以下两种语法之一:while() 或 while()。声明使用“=”,看起来像表达式,但它是一个不同的语法实体。

当你写作时

while(int i = 1) {
}

,这很好。 “int i=1”是一个声明。但是,你想要的是

while ( (int i = 1) + 3) {
}

这是一种非常不同的动物。您需要在 while() 中使用表达式,其中表达式的一项是声明。现在,声明是一个语句,因此不能成为表达式的一部分。这就是为什么你需要做的事情不能做。

(在写完整个咆哮之后,我注意到另外两个人也写了同样的东西。哦,越多越好。)

【讨论】:

    【解决方案3】:

    这似乎不是合规行为。标准第 6.5.1.2 部分规定:

    当while语句的条件是声明时,声明的变量的作用域extends 从它的声明点 (3.3.1) 到 while 语句的结尾。表单的while语句

    while (T t = x) 语句

    等价于

    label:
    { //start of condition scope
        T t = x;
        if (t) {
            statement
            goto label;
        }
    }
    

    因此,在您的示例中, ch 应该在循环范围内声明并正常工作(通过每次循环迭代重新创建它)。观察到的行为的原因很可能是由于编译器没有正确确定变量的范围,然后多次声明它。

    【讨论】:

    • 编译器完全兼容,不可能做到问题所要求的。请参阅下面的答案。
    【解决方案4】:

    可能是因为 while 子句的内容在每个循环中都会被评估,因此它会尝试多次声明“ch”。

    您给出的 if、switch 和 for 循环示例都将只定义一次“ch”。

    【讨论】:

      【解决方案5】:

      可以在 while 循环的测试表达式中放置一个变量声明。你不能做的是将声明语句放在其他表达式中。例如,在表达式 a+b+c 中,您不能将 b 替换为 int i = f()。表达式 (a) 也一样;您不能插入 int i=f() 来获得表达式 (int i=f())

      因此,在while (int i = foo()) 中,最外面的括号是while 语句的一部分,而不是文本表达式的一部分,并且一切都是合法的。在while ((int i = foo())) 中,最外面的括号仍然是while 语句的一部分。测试表达式的格式为"(" expr ")",最终会出现语法错误。

      【讨论】:

      • 我不明白In while ((int i = foo())), the outermost brackets are still part of the while statement. The test-expression would have the form "(" expr ")", and you end up with a syntax error. ,特别是段落中的最后一句,用更好的例子解释一下? ,非常感谢:)
      • 我的理解是我可以声明变量 x in while 例如 while(int x=...) 但初始化部分,即 ... 必须包含表达式而不是任何声明,对吧?
      • @Mr.Anubis:你不能使用(( )),因为内部() 本身就是一个表达式,你不能在其中声明。外部() 属于while 并且不形成表达式。是的,x 的初始化程序本身必须是一个有效的表达式,并且不能包含第二个声明。
      【解决方案6】:

      试试 这行不通

      while (int ch = stream.get(), ch != -1) ...
      

      我从未尝试过,但如果您编辑中的评论是正确的,这应该可以。
      VS 2005 甚至不会编译它。

      【讨论】:

      • 这段代码被编译器解释为:int ch = (stream.get(), ch != -1)
      • 根据我的消息来源,逗号运算符位于优先级的底部 - 但我的构造还有其他问题。
      • 因为逗号运算符不允许声明语句出现在其中。但是分配会起作用int i; while(i = 0, ++i); 请参阅 [expr.comma]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-26
      • 2011-01-09
      • 2014-03-28
      • 1970-01-01
      • 2020-02-03
      • 2011-12-23
      相关资源
      最近更新 更多