简体   繁体   中英

Do-While Loop within Switch Statement in C++

#include <iostream>

using namespace std;

int main(int argc, char *argv[]) {
    int n = 12;
    int q = (n + 3) / 4;
    
    cout << q;
    cout << ' ';
    cout << n%4;
    cout << ' ';
    
    switch (n % 4) { 
        case 0:  cout << n; cout << ' ';
            do { n++; cout << n; cout << ' ';
        case 3: n++; cout << n; cout << ' ';
        case 2: n++;
        case 1: n++; cout <<n;  cout << ' ';
            
        } while (--q > 0);
    }
    
    cout << n; 
}

With the above code, I got the following:

3 0 12 13 14 16 17 18 20 21 22 24 24

I am not familiar with C++ language.

Why does it falls through in the second and third iteration of the while loop?

Does the switch case statement save the initial n%4 value and apply that during the do-while loop?

case labels are just labels.

To make it more clear you may rewrite the switch statement the following way when the expression n % 4 is equal to 0.

goto Label0;
{ 
    Label0:  cout << n; cout << ' ';
        do { n++; cout << n; cout << ' ';
    n++; cout << n; cout << ' ';
    n++;
    n++; cout <<n;  cout << ' ';
        
    } while (--q > 0);
}

So if you will run your program with the modification

#include <iostream>
using namespace std;

int main() 
{
    int n = 12;
    int q = (n + 3) / 4;
    
    cout << q;
    cout << ' ';
    cout << n%4;
    cout << ' ';
    
    goto Label0;
    { 
        Label0:  cout << n; cout << ' ';
        do { n++; cout << n; cout << ' ';
            n++; cout << n; cout << ' ';
            n++;
            n++; cout <<n;  cout << ' ';
        } while (--q > 0);
    }
    
    cout << n;  return 0;
}

you will get the same result.

3 0 12 13 14 16 17 18 20 21 22 24 24

"Switch-cases" always fall through, unless you explicitly break out of the switch.

The switch-case construct is essentially a glorified bunch of goto s, but more robust than one constructed manually.

(Your code looks like a slightly mutated version of the legendary "Duff's device", a loop-unrolling construct that has confused generations of C programmers.)

Translated into unstructured "goto code", your switch is logically equivalent to

    int x = n % 4;
    if (x == 0)
        goto zero;
    if (x == 1)
        goto one;
    if (x == 2)
        goto two;
    if (x == 3)
        goto three;
  zero:
    cout << n << ' ';
  loop:
    n++;
    cout << n << ' ';
  three:
    n++;
    cout << n << ' ';
  two:
    n++;
  one:
    n++;
    cout << n << ' ';
  if (--q > 0)
      goto loop;

but the compiler might be able to create more efficient code from the switch than that series of conditionals, by using an actual jump table.


Footnote: gcc actually allows you to use labels as values and jump to them, so you could create exactly such a table yourself;

    void* table = { &&zero, &&one, &&two, &&three };
    goto *table[n % 4];
  zero:
    cout << n << ' ';
  loop:
    n++;
    cout << n << ' ';
  three:
    n++;
    cout << n << ' ';
  two:
    n++;
  one:
    n++;
    cout << n << ' ';
  if (--q > 0)
      goto loop;

(Not that you should , but you could . A good compiler will compile your switch to something similar to this if it is beneficial, which it knows more about than a mere human.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM