[In this reprinted #altdevblogaday in-depth piece, Gamer Camp's Alex Darby continues his series on a C/C++ Low Level Curriculum by looking at the conditional operator and switch statements.] Hello humans. Welcome to the seventh part of the C/C++ Low Level Curriculum series I've been writing. This post covers the conditional operator, and switch statements. As per usual I will be showing snippets of C++ code and throwing the corresponding x86 assembler at you (as produced by VS2010) to show you what your high level code is actually doing at the assembler level. Disclaimer: in an ideal world, I'd like to try to avoid assumed knowledge, but keeping up the level of detail in each post that this entails is, frankly, too much work. Consequently, I will from now on point you at post 6 as a "how to" and then get on with it… Here are the backlinks for preceding articles in the series (warning: it might take you a while, the first few are quite long):
A Low Level Curriculum for C and C++
C / C++ Low Level Curriculum part 2: Data Types
C / C++ Low Level Curriculum Part 3: The Stack
C / C++ Low Level Curriculum: More Stack
C / C++ Low Level Curriculum Part 5: Even More Stack
C / C++ Low Level Curriculum Part 6: Conditionals [see near the top of this post for details on compiling & running the code snippets]
The conditional operator I assume that everyone's familiar with the conditional operator, also known as the "question mark", or the ternary operator ("ternary" because it's the only C/C++ operator that takes three operands). If you're not, here's a link so you can catch up (I predict that you will be so stoked to find out about it that you will be over-using it within the week). Personally I heartily approve of the conditional operator when used judiciously, but it's not always great for source level debugging because it's basically a single line if-else and can be hard to follow in the debugger (in fact I've heard of it being banned under the coding standards at more than one company, but there you are we can't all be sane can we?). Anyway, let's have a quick look at it with some code:
#include "stdafx.h" int main(int argc, char* argv[]) { // the line after this comment is logically equivalent to the following line of code: // int iLocal; if( argc > 2 ){ iLocal = 3; }else{ iLocal = 7; } int iLocal = (argc > 1) ? 3 : 7; return 0; }
If you remember the the assembler that a basic if-else generated in the last article, then the assembler generated here will probably bust your mind gaskets… Note:
I've deliberately left the function prologue and epilogue out of the asm below, and just left the assembler involved with the conditional assignment
if your disassembly view doesn't show the variable names, then you need to right click the window and check "Show Symbol Names"
5: int iLocal = (argc > 2) ? 3 : 7; 01311249 xor eax,eax 0131124B cmp dword ptr [argc],2 0131124F setle al 01311252 lea eax[eax*4+3] 01311259 mov dword ptr [iLocal],eax
Clearly this is not very much like the code for the simple if-else that we looked at previously. This is because there is trickery afoot and the compiler has chosen to do sneaky branchless code to implement the logic specified by the C++ code. So, let's examine it line by line:
line 1 – uses the xor instruction to set eax to 0. Anything XORed with itself is 0.
line 2 – as in the previous if examples this uses cmp to test the condition, setting flags in a special purpose CPU register based on the result of the comparison.
line 3 – this is a new one! The instruction setless equal sets its operand to 1 if the 1st operand of the preceding cmp was less than or equal to the 2nd operand, and to 0 if it was greater. We've not seen the operand al before, it's a legacy (386) register name which no
No tags.