Thread: Quick question concerning switch statements

  1. #16
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,820
    Didn't I say that in the first place....?
    Switches have to be constant...so you could just use a series of ifs
    Woop?

  2. #17
    Registered User
    Join Date
    Aug 2008
    Posts
    8
    Quote Originally Posted by Shaun32887 View Post
    This code won't work, I'm assuming it's because the case can't be a logical statement.

    The actual program I'm working on would use a much more complex switch than this, this is simply a small example of the concept.

    Code:
    #include <iostream>
    using namespace std;
    
    int main( )
    {
        int x = 1;
        switch (x)
        {
        case (0 || 1):
            cout << "X is either 0 or 1" << endl;
            break;
        case (1 || 2):
            cout << "X is either 1 or 2" << endl;
            break;
        case (2 || 3):
            cout << "X is either 2 or 3" << endl;
            break;
        }
        system("pause");
        return 0;
    }
    My question is, what's the easiest way to accomplish similar results?

    Ideally, I'd want the output generated to be

    X is either 0 or 1
    X is either 1 or 2

    Thanks
    As I understand it, switch statement is kind of like an array of instructions. A jump table is created, which is like an array of pointers to the code for each case. I.e., for case 1, the code at address jump_table[1] is executed. case 2, the code at jump_table[2] is executed, and so on. That makes using the switch much faster than a long chain of if/else statements, for the same reason that it's quicker to go to the nth element in an array than it is in a linked list (although a good compiler might optimize away that long chain of if/else statements into something like a switch). I know I'm not answering your question, but I hope it clears switches up a bit.

    Also, I think statements like 0 || 1, 1 || 2, 2 || 3, etc. evaluate (as integers) to 1 if either operand is non-zero, and zero in the case 0 || 0, since || is a boolean and not an integer operator.


    I.e., 2 || 3 evaluates to int(bool(2) || bool(3))
    which evals to int(true || true)
    which evals ti int(true)
    which evals to 1

  3. #18
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by 3rdcoast View Post
    As I understand it, switch statement is kind of like an array of instructions. A jump table is created, which is like an array of pointers to the code for each case. I.e., for case 1, the code at address jump_table[1] is executed. case 2, the code at jump_table[2] is executed, and so on. That makes using the switch much faster than a long chain of if/else statements, for the same reason that it's quicker to go to the nth element in an array than it is in a linked list (although a good compiler might optimize away that long chain of if/else statements into something like a switch). I know I'm not answering your question, but I hope it clears switches up a bit.

    Also, I think statements like 0 || 1, 1 || 2, 2 || 3, etc. evaluate (as integers) to 1 if either operand is non-zero, and zero in the case 0 || 0, since || is a boolean and not an integer operator.


    I.e., 2 || 3 evaluates to int(bool(2) || bool(3))
    which evals to int(true || true)
    which evals ti int(true)
    which evals to 1
    Hmm... Strange. I always thought a switch was just an easier way of writing an if/else if chain, but according to the assembly output the if/else if chain is actually shorter:
    Code:
    int main()
    {
    00401800  push        ebp  
    00401801  mov         ebp,esp 
    00401803  sub         esp,8 
    	int i = 0;
    00401806  mov         dword ptr [i],0 
    	cin >> i;
    0040180D  lea         eax,[i] 
    00401810  push        eax  
    00401811  mov         ecx,dword ptr [__imp_std::cin (40203Ch)] 
    00401817  call        dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402038h)] 
    
    	switch ( i )
    0040181D  mov         ecx,dword ptr [i] 
    00401820  mov         dword ptr [ebp-8],ecx 
    00401823  cmp         dword ptr [ebp-8],0 
    00401827  je          main+37h (401837h) 
    00401829  cmp         dword ptr [ebp-8],1 
    0040182D  je          main+40h (401840h) 
    0040182F  cmp         dword ptr [ebp-8],2 
    00401833  je          main+49h (401849h) 
    00401835  jmp         main+50h (401850h) 
    	{
    	case 0:
    		i = 10;
    00401837  mov         dword ptr [i],0Ah 
    		break;
    0040183E  jmp         main+50h (401850h) 
    	case 1:
    		i = 11;
    00401840  mov         dword ptr [i],0Bh 
    		break;
    00401847  jmp         main+50h (401850h) 
    	case 2:
    		i = 12;
    00401849  mov         dword ptr [i],0Ch 
    		break;
    	}
    
    	return 0;
    00401850  xor         eax,eax 
    }
    Code:
    int main()
    {
    00401800  push        ebp  
    00401801  mov         ebp,esp 
    00401803  push        ecx  
    	int i = 0;
    00401804  mov         dword ptr [i],0 
    	cin >> i;
    0040180B  lea         eax,[i] 
    0040180E  push        eax  
    0040180F  mov         ecx,dword ptr [__imp_std::cin (40203Ch)] 
    00401815  call        dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402038h)] 
    
    	if ( i == 0 )
    0040181B  cmp         dword ptr [i],0 
    0040181F  jne         main+2Ah (40182Ah) 
    		i = 10;
    00401821  mov         dword ptr [i],0Ah 
    00401828  jmp         main+46h (401846h) 
    	else if ( i == 1 )
    0040182A  cmp         dword ptr [i],1 
    0040182E  jne         main+39h (401839h) 
    		i = 11;
    00401830  mov         dword ptr [i],0Bh 
    00401837  jmp         main+46h (401846h) 
    	else if ( i == 2 )
    00401839  cmp         dword ptr [i],2 
    0040183D  jne         main+46h (401846h) 
    		i = 12;
    0040183F  mov         dword ptr [i],0Ch 
    
    	return 0;
    00401846  xor         eax,eax 
    }

  4. #19
    Registered User
    Join Date
    Aug 2008
    Posts
    8
    Quote Originally Posted by cpjust View Post
    Hmm... Strange. I always thought a switch was just an easier way of writing an if/else if chain, but according to the assembly output the if/else if chain is actually shorter:
    Code:
    int main()
    {
    00401800  push        ebp  
    00401801  mov         ebp,esp 
    00401803  sub         esp,8 
    	int i = 0;
    00401806  mov         dword ptr [i],0 
    	cin >> i;
    0040180D  lea         eax,[i] 
    00401810  push        eax  
    00401811  mov         ecx,dword ptr [__imp_std::cin (40203Ch)] 
    00401817  call        dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402038h)] 
    
    	switch ( i )
    0040181D  mov         ecx,dword ptr [i] 
    00401820  mov         dword ptr [ebp-8],ecx 
    00401823  cmp         dword ptr [ebp-8],0 
    00401827  je          main+37h (401837h) 
    00401829  cmp         dword ptr [ebp-8],1 
    0040182D  je          main+40h (401840h) 
    0040182F  cmp         dword ptr [ebp-8],2 
    00401833  je          main+49h (401849h) 
    00401835  jmp         main+50h (401850h) 
    	{
    	case 0:
    		i = 10;
    00401837  mov         dword ptr [i],0Ah 
    		break;
    0040183E  jmp         main+50h (401850h) 
    	case 1:
    		i = 11;
    00401840  mov         dword ptr [i],0Bh 
    		break;
    00401847  jmp         main+50h (401850h) 
    	case 2:
    		i = 12;
    00401849  mov         dword ptr [i],0Ch 
    		break;
    	}
    
    	return 0;
    00401850  xor         eax,eax 
    }
    Code:
    int main()
    {
    00401800  push        ebp  
    00401801  mov         ebp,esp 
    00401803  push        ecx  
    	int i = 0;
    00401804  mov         dword ptr [i],0 
    	cin >> i;
    0040180B  lea         eax,[i] 
    0040180E  push        eax  
    0040180F  mov         ecx,dword ptr [__imp_std::cin (40203Ch)] 
    00401815  call        dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402038h)] 
    
    	if ( i == 0 )
    0040181B  cmp         dword ptr [i],0 
    0040181F  jne         main+2Ah (40182Ah) 
    		i = 10;
    00401821  mov         dword ptr [i],0Ah 
    00401828  jmp         main+46h (401846h) 
    	else if ( i == 1 )
    0040182A  cmp         dword ptr [i],1 
    0040182E  jne         main+39h (401839h) 
    		i = 11;
    00401830  mov         dword ptr [i],0Bh 
    00401837  jmp         main+46h (401846h) 
    	else if ( i == 2 )
    00401839  cmp         dword ptr [i],2 
    0040183D  jne         main+46h (401846h) 
    		i = 12;
    0040183F  mov         dword ptr [i],0Ch 
    
    	return 0;
    00401846  xor         eax,eax 
    }
    Did you compile with no optimization? A switch statement shouldn't result in comparisons being done for every possible value (the list of cmp and je statements bunched together in the first example). It kind of defeats the purpose of having a switch statement in the language (an if/else chain is certainly more readable and less error prone, since it doesn't need the case labels or break statements).

    Maybe the assembly for the switch program came out like that since there are so few cases (0,1,2, and default).
    Last edited by 3rdcoast; 08-01-2008 at 10:44 PM.

  5. #20
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by 3rdcoast View Post
    Did you compile with no optimization? A switch statement shouldn't result in comparisons being done for every possible value (the list of cmp and je statements bunched together in the first example). It kind of defeats the purpose of having a switch statement in the language (an if/else chain is certainly more readable and less error prone, since it doesn't need the case labels or break statements).

    Maybe the assembly for the switch program came out like that since there are so few cases (0,1,2, and default).
    I used VC++ 2008 express in Release mode. Maybe gcc could optimize better?

    Although I don't see how a switch could possibly not check each case? It would have to be psychic then. I can try adding more cases to see if that makes a difference...
    One more thing that has me confused is why VC++ used a sub instruction on the 3rd line after main() in the switch version and a push in the if/else version? I'm not that great with assembly, so I don't have a clue why it's different.

  6. #21
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Quote Originally Posted by Shaun32887 View Post
    Yeah, you're right. I was thinking of another less efficient way to write the if statements.



    Still, I would have the same problem.


    Code:
    #include <iostream>
    using namespace std;
    
    int main( )
    {
        int x = 1;
    
        if (x == 0 ||x == 1)
            cout << "X is either 0 or 1" << endl;
        else if (x == 1 ||x == 2)
            cout << "X is either 1 or 2" << endl;
        else if (x == 2 ||x == 3)
            cout << "X is either 2 or 3" << endl;
        system("pause");
        return 0;
    }
    This would still only display

    "X is either 0 or 1"

    Since it won't execute ALL the satisfied branches, just the 1st satisfied branch.


    I think the conditional fallthrough might be my solution.
    While someone provided an answer here is another possible one:
    Code:
    switch(x)
    {
      case 0:
        cout<<"X is either 0 or 1"<<endl;
        break;
      case 1:
        cout<<"X is either 0 or 1"<<endl;
        cout<<"X is either 1 or 2"<<endl;
        break;
      case 2:
        cout<<"X is either 1 or 2"<<endl;
        cout<<"X is either 2 or 3"<<endl;
        break;
      case 3:
        cout<<"X is either 2 or 3"<<endl;
        break;
    }

  7. #22
    Registered User
    Join Date
    Aug 2008
    Posts
    8
    Quote Originally Posted by cpjust View Post
    I used VC++ 2008 express in Release mode. Maybe gcc could optimize better?

    Although I don't see how a switch could possibly not check each case? It would have to be psychic then. I can try adding more cases to see if that makes a difference...
    One more thing that has me confused is why VC++ used a sub instruction on the 3rd line after main() in the switch version and a push in the if/else version? I'm not that great with assembly, so I don't have a clue why it's different.
    My best guess is that the compiler determined the brute force way wasn't too bad with 4 cases. Either that, or MS wants you to buy the pro compiler to get the benefits of using jump tables in switches (wow, that would suck if VC Express is crippled that badly).

    Briefly, here's what Patterson & Hennessey (not the Hennessey & Patterson book!) has to say:

    Quote Originally Posted by Computer Organization and Design: The Hardware / Software Interface
    Case/Switch Statement

    Most programming languages have a case or switch statement that allows the programmer to select one of many alternatives depending on a single value. The simplest way to implement switch is via a sequence of conditional tests, turning the switch statement into a chain of if-then-else statements.

    Sometimes the alternatives may be more efficiently encoded as a table of addresses of alternative instruction sequences, called a jump address table, and the program needs only to index into the table and then jump to the appropriate sequence. The jump table is then just an array of words containing the addresses that correspond to labels in the code.
    Maybe Microsoft just hates C++ and is sabotaging it to force you to use C#. :lol

    No seriously, in Visual Studio 2005 (Pro!) you'll get deprecation warnings when using STL algorithms. I'll give you an example of of copying an array using STL:

    Code:
    #include <algorithm>   /* std::copy */
    int	main()
    {
    	int A[] = {1,2,3,4,5,6,7,8,9,10};
    	int B[10];
    
    	std::copy(&A[0],&A[10],&B[0]);
    
    	return	0;
    }
    This produces the following warning:
    Code:
    >------ Build started: Project: somecrap, Configuration: Debug Win32 ------
    1>Compiling...
    1>main.cpp
    1>f:\apps\visual-studio\vc\include\xutility(2282) : warning C4996: 'std::_Copy_opt' was
    1>        declared deprecated
    1>        f:\apps\visual-studio\vc\include\xutility(2270) : see declaration of 'std::_Copy_opt'
    1>        Message: 'You have used a std:: construct that is not safe. See documentation on how to use
    1>        the Safe Standard C++ Library'
    1>        f:\code\visual\somecrap\somecrap\main.cpp(121) : see reference to function template
    1>        instantiation   '_OutIt std::copy<int*__w64 ,int*__w64 >(_InIt,_InIt,_OutIt)' being compiled
    1>        with
    1>        [
    1>            _OutIt=int *__w64 ,
    1>            _InIt=int *__w64 
    1>        ]
    1>Linking...
    1>Embedding manifest...
    1>Build log was saved at "file://f:\code\visual\somecrap\somcrap\Debug\BuildLog.htm"
    1>somecrap - 0 error(s), 1 warning(s)
    ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
    LMAO @ Microsoft telling me not to use the STL!
    Last edited by 3rdcoast; 08-02-2008 at 12:10 AM.

  8. #23
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by 3rdcoast View Post
    No seriously, in Visual Studio 2005 (Pro!) you'll get deprecation warnings when using STL algorithms. I'll give you an example of of copying an array using STL:

    Code:
    #include <algorithm>   /* std::copy */
    int	main()
    {
    	int A[] = {1,2,3,4,5,6,7,8,9,10};
    	int B[10];
    
    	std::copy(&A[0],&A[10],&B[0]);
    
    	return	0;
    }
    This produces the following warning:
    Code:
    >------ Build started: Project: somecrap, Configuration: Debug Win32 ------
    1>Compiling...
    1>main.cpp
    1>f:\apps\visual-studio\vc\include\xutility(2282) : warning C4996: 'std::_Copy_opt' was
    1>        declared deprecated
    1>        f:\apps\visual-studio\vc\include\xutility(2270) : see declaration of 'std::_Copy_opt'
    1>        Message: 'You have used a std:: construct that is not safe. See documentation on how to use
    1>        the Safe Standard C++ Library'
    1>        f:\code\visual\somecrap\somecrap\main.cpp(121) : see reference to function template
    1>        instantiation   '_OutIt std::copy<int*__w64 ,int*__w64 >(_InIt,_InIt,_OutIt)' being compiled
    1>        with
    1>        [
    1>            _OutIt=int *__w64 ,
    1>            _InIt=int *__w64 
    1>        ]
    1>Linking...
    1>Embedding manifest...
    1>Build log was saved at "file://f:\code\visual\somecrap\somcrap\Debug\BuildLog.htm"
    1>somecrap - 0 error(s), 1 warning(s)
    ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
    LMAO @ Microsoft telling me not to use the STL!
    Damn! I've seen those warnings for a lot of C functions, but I've never seen it for STL before. That's hilarious!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Quick question about types...
    By Elysia in forum C++ Programming
    Replies: 32
    Last Post: 12-07-2008, 05:39 AM
  2. While Statements Question
    By thekautz in forum C++ Programming
    Replies: 4
    Last Post: 11-09-2008, 02:48 PM
  3. Using a character array in a switch question.
    By bajanElf in forum C Programming
    Replies: 10
    Last Post: 11-08-2008, 08:06 AM
  4. i need alil help with my switch question
    By datainjector in forum C Programming
    Replies: 17
    Last Post: 06-29-2002, 08:14 PM
  5. Quick question: exit();
    By Cheeze-It in forum C Programming
    Replies: 6
    Last Post: 08-15-2001, 05:46 PM