【问题标题】:Separate scope for switch cases with static variables with the same name [closed]具有相同名称的静态变量的开关案例的单独范围[关闭]
【发布时间】:2014-03-29 06:43:45
【问题描述】:

更新:我现在重新测试了简化的测试用例和恢复共享名称的完整代码,并且它可以正常工作。我的代码中的其他地方可能还有其他错误,现在已修复。很抱歉浪费您的时间和精力;将来不会在没有工作测试用例的情况下发布。 过失。


我有一个反复调用的 C++ 函数。它里面有下面的sn-p

     switch(c)
     {
     case 1:
        {
          static int i = 0;
          if ( ... )  { i = 0; }
          .... 
          break;
        }
     case 2:
        {
          static int i = 0;
          if ( ... )  { i = 0; }
          .... 
          break;
        }
     case 3:
        {
          static int i = 0;
          if ( ... )  { i = 0; }
          .... 
          break;
        }
     }

这个想法是它必须记住每个案例的状态,有时它必须重置它。

它没有正常工作。当我调试它(​​MSVC++ 2010 Express Edition)时,我注意到每个i 的行为并不是独立的,它们的值似乎在自行变化;此外,当重置条件被触发时,相应的if 输入正常,但i = 0; 语句只是...... 跳过! “locals”窗口显示i,其先前的值保持不变(而当前语句是下一个语句,仍在if 内)。 if 中的其他语句正在正常执行。

当我用唯一的名称(i1i2i3)重命名每个 i 时,问题就消失了。

这是一些错误,还是我应该知道的一些语言特性?我认为每个块{ ... } 都定义了独立的范围。这里发生了什么?它可以在 C 中工作吗?

编辑:很抱歉没有构建测试用例。会这样做,稍后再报告。

【问题讨论】:

  • 您能否提供一个测试用例来准确展示您所看到的内容? (即一个小程序,预期的输出和(意外的)实际输出。)如果它确实将所有这些变量视为相同,那么这是一个错误;但不可能从示例代码中看出你的真实代码可能是什么样子。
  • 我不能,不能及时,抱歉。但是任何简单的事情都可以。比如说,当(每个)i 命中 4 时,将其重置为 0;当它是==c 时,打印出来。然后使用c = 1,2,1,3,1,2,1,3,1,2,1,3,1,2,1... 调用函数,应该会出现错误。跨度>
  • 很遗憾,如果您不能提供代码来演示问题,我们无法猜测问题可能是什么。它们都应该是自变量;如果它们表现得好像不是,那么编译器、您的代码或您对其行为的解释中存在错误。我怀疑不是编译器。
  • @ДарВетер 我的回答显示了一个“简单的事情”,当然不会重现您所描述的问题。您应该在自己的调试过程中构建测试用例,早在此处发布之前!当你最终在这里发布时,你应该发布测试用例。 (另外,哪个版本的 MSVC++?有很多。)谢谢!
  • @MikeSeymour 我会的,只是需要一些时间。

标签: c++ c static scope switch-statement


【解决方案1】:

这听起来像是您的代码或解释中的错误。我可以想象调试器中的“监视窗口”功能会出错,因为块没有名称,因此很难在文本中识别。

具有static 存储持续时间的局部变量受块范围约束。

这是他们确实具有函数范围的证据:

[C++11: 3.3.5/1]: 标签 (6.1) 具有函数作用域,可以在声明它们的函数中的任何位置使用。 只有标签有功能范围。

这是一个实际的演示:

#include <iostream>

void f(const int i)
{
    switch (i) {
        case 3: {
            static int x = 0;
            std::cout << x;
            x = 3;
            std::cout << x << ' ';
            break;
        }

        case 4: {
            static int x = 0;
            std::cout << x;
            x = 4;
            std::cout << x << ' ';
            break;
        }
    }
}

int main()
{
    f(3);
    f(4);
}

// Output: 03 04

这表明当输入第二种情况时,您正在使用不同的本地静态变量x。否则你会看到03 34

Live demo using GCC 4.8;我使用 Visual Studio 2012 得到了相同的结果。

【讨论】:

  • 我的 Firefox 在自动刷新这个网站方面真的很烂。
  • 在某处是否有可点击的标准链接?如果是 PDF,那也很好。
  • +1 表示调试器监视理论,这很可能是问题的原因。
  • 没有错误;我用共享名称再次运行它并且它有效。我的代码中的某处可能还有其他错误。这将教会我永远不要在没有工作测试代码的情况下发布。抱歉,非常感谢。
【解决方案2】:

函数内的静态变量具有块作用域,并且它们在连续调用它时是持久的。您不能在同一范围内声明两个具有相同名称的变量,但如果它们位于不同的范围内,则可以这样做,表示为

{}

这是你的情况。

switch(c)
 {
 case 1:
    {
      static int i = 0;
    }
 case 2:
    {
      static int i = 0;
    }
 case 3:
    {
      static int i = 0; 
    }
 }

因此这应该可以按您的预期工作,因此这可能是编译器、调试器(或在没有给出更多信息的情况下难以猜测的其他地方)中的错误,它将所有这些静态变量视为同一个变量。这就是为什么更改这些变量的名称可以解决您的问题。

【讨论】:

    【解决方案3】:

    我必须自己检查一下,我想我会分享我的小测试。变量仅在大小写大括号内可见。并且可以在另一个案例中声明相同的变量名,并且不会覆盖另一个变量。

    变量在函数中是不可见的,只能在 switch 语句的大括号内。

    #include<stdio.h>
    int call_switch(int);
    int main()
    {
    call_switch(2);
    call_switch(3);
    call_switch(2);
    call_switch(3);
    return 0;
    }
    
    int call_switch(int a){
    switch(a)
    { 
       case 2:
       {
         static int i = 5;
         i++;
         printf(" i declared as 5     %d\n",i);
         break;
       }
       case 3:
       {
         static int i = 10;
         i++;
         printf("i declared as 10   %d\n",i);
         break;
       }
    }
      // printf("%d",i ); not visible here
      return 0;
    
    }
    

    输出是

    i declared as  5     6
    i declared as 10    11
    i declared as  5     7
    i declared as 10    12
    

    【讨论】:

      【解决方案4】:

      static 函数内的变量具有函数作用域。该变量在整个函数中都是可见的。

      static函数外的变量有文件作用域,在文件内部可见,但跨文件不可见。

      【讨论】:

      • 编译器不会给出关于同一变量的多个声明的错误吗?你能给我一个链接到一些关于这个的文档吗? ——不是每个块都定义了一个单独的范围吗?我认为不可能引用该块之外的 {...} 块内定义的变量,即使在同一个函数内也是如此。 (?)
      • 它看到变量 declaration 在另一个 block {} 中,这就是它不产生任何警告的原因
      • 我认为不可能引用该块之外的 {...} 块内定义的变量,即使在同一个函数内也是如此。 (?)所以它们必须是单独的变量,不是吗?
      • 不,静态变量有 block 范围;这些应该是单独的变量,因为它们位于单独的块中。如果编译器确实将它们折叠成一个变量,那么这是一个错误。 (我怀疑问题出在解释调试器的输出上)。
      • 这个答案是完全错误的,没有回答问题。标准定义的功能范围仅与goto-labels有关。即便如此,这个问题中的静态数据仍然存在于每个案例中的本地块中。它们具有块范围
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多