Home c# if else vs. switch case in C #

if \ else vs. switch \ case in C #

Author

Date

Category

What is better to use: if \ else or switch \ case

?

int a = 3;
if (a == 1)
{
  ...
}
else if (a == 2)
{
  ...
}
ELSE.
{
  ...
}
switch (a)
{
  Case 1:
    ...
    Break;
  Case 2:
    ...
    Break;
  Default:
    ...
    Break;
}
  • Which of these structures is faster? Why?
  • When to use one or the other?

Answer 1, Authority 100%

Both conditional operator working at the same speed. Since the level of machine instructions are converted to the same instructions.

Choose only makes sense for taste and for the task.

switch can be operated with only one variable. In if are no such restrictions.

In my opinion, C # language is too high-level for this kind of optimization.

Write readable code;)


Answer 2, Authority 183%

The answer above is not quite correct, even with the comment.

If the values ​​are close, for example:

switch (x)
{
  case 0: / * * / break;
  case 1: / * * / break;
  case 2: / * * / break;
  case 3: / * * / break;
  case 4: / * * / break;
  case 5: / * * / break;
}

In this case, the compiler generates a transition table (jump table) (IL-code):

switch (IL_0043, IL_004e, IL_0059, IL_0064, IL_006f, IL_007a)

Hours such table O (1) . No need to worry if a few missing values, and they do not go, one after another, in this case, the compiler still generates a jump table:

switch (x)
{
  case 0: / * * / break;
  case 1: / * * / break;
  case 2: / * * / break;
  case 3: / * * / break;
  case 4: / * * / break;
  case 5: / * * / break;
  case 9: / * * / break;
  case 13: / * * / break;
}

IL:

switch (IL_0043, IL_004e, IL_0059, IL_0064, IL_006f, IL_007a, IL_009a, IL_009a, IL_009a, IL_0085, IL_009a, IL_009a, IL_009a, IL_0090)

As you can see, the “hole” filled with passages for the end of construction switch : IL_009a

If the distance between the values ​​is too large for the construction of a single table, the compiler can divide them into 2+ table. For example:

switch (x)
{
  case 0: / * * / break;
  case 1: / * * / break;
  case 2: / * * / break;
  case 3: / * * / break;
  case 2000000000: / * * / break;
  case 2000000001: / * * / break;
  case 2000000002: / * * / break;
  case 2000000003: / * * / break;
  case 2000000004: / * * / break;
}

IL:

IL_0004: ldloc.0
IL_0005: switch (IL_0037, IL_0042, IL_004d, IL_0058)
IL_001a: ldloc.0
IL_001b: ldc.i4 2000000000
IL_0020: sub
IL_0021: switch (IL_0063, IL_006e, IL_0079, IL_0084)

As seen from the above example, the compiler highlighted 2 transition table. For other table of values ​​is subtracted 2,000,000,000 . In general, the speed of the O (1) or O (m) , where m – number of groups

.

Let’s see what will happen in the general case. I took 20 random numbers:

switch (x)
{
  case 955626049: / * * / break;
  case 1732096473: / * * / break;
  case 1416261125: / * * / break;
  case 901627868: / * * / break;
  case 713886433: / * * / break;
  case 289231272: / * * / break;
  case 598309392: / * * / break;
  case 1284278823: / * * / break;
  case 1517161566: / * * / break;
  case 1548994144: / * * / break;
  case 1854092737: / * * / break;
  case 1725885116: / * * / break;
  case 1984539276: / * * / break;
  case 558794563: / * * / break;
  case 337975821: / * * / break;
  case 1687544575: / * * / break; 
Case 1048183578: / * * / Break;
  CASE 102389471: / * * / BREAK;
  Case 1017837673: / * * / Break;
  CASE 1012360293: / * * / BREAK;
}

In this case, the compiler sorts them, and is looking for a binary search:

il_0004: ldloc.0
IL_0005: LDC.I4 1017837673
IL_000A: BGT IL_0099
IL_000F: LDLOC.0.
IL_0010: LDC.I4 598309392
IL_0015: BGT.S IL_0058
IL_0017: LDLOC.0
IL_0018: LDC.I4 289231272
IL_001D: BGT.S IL_0036
IL_001F: LDLOC.0.
IL_0020: LDC.I4 102389471
IL_0025: BEQ IL_016E
IL_002A: LDLOC.0.
IL_002B: LDC.I4 289231272
IL_0030: BEQ IL_0126
IL_0035: RET.
IL_0036: LDLOC.0.
IL_0037: LDC.I4 337975821
IL_003C: BEQ IL_015C
IL_0041: LDLOC.0.
IL_0042: LDC.I4 558794563
IL_0047: BEQ IL_0156
IL_004C: LDLOC.0.
IL_004D: LDC.I4 598309392
IL_0052: BEQ IL_012C
IL_0057: RET.
IL_0058: LDLOC.0
IL_0059: LDC.I4 901627868
IL_005E: BGT.S IL_0077
IL_0060: LDLOC.0.
IL_0061: LDC.I4 713886433
IL_0066: BEQ IL_0120
IL_006B: LDLOC.0.
IL_006C: LDC.I4 901627868
IL_0071: BEQ IL_011A
IL_0076: RET.
IL_0077: LDLOC.0
IL_0078: LDC.I4 955626049
IL_007D: BEQ IL_0108
IL_0082: LDLOC.0.
IL_0083: LDC.I4 1012360293
IL_0088: BEQ IL_017A
IL_008D: LDLOC.0
IL_008E: LDC.I4 1017837673
IL_0093: BEQ IL_0174
IL_0098: RET.
IL_0099: LDLOC.0.
IL_009A: LDC.I4 1548994144
IL_009F: BGT.S IL_00D6
IL_00A1: LDLOC.0.
IL_00A2: LDC.I4 1284278823
IL_00A7: BGT.S IL_00BD
IL_00A9: LDLOC.0
IL_00AA: LDC.I4 1048183578
IL_00AF: BEQ IL_0168
IL_00B4: LDLOC.0
IL_00B5: LDC.I4 1284278823
IL_00BA: BEQ.S IL_0132
IL_00BC: RET.
IL_00BD: LDLOC.0.
IL_00BE: LDC.I4 1416261125
IL_00C3: BEQ.S IL_0114
IL_00C5: LDLOC.0.
IL_00C6: LDC.I4 1517161566
IL_00CB: BEQ.S IL_0138
IL_00CD: LDLOC.0.
IL_00CE: LDC.I4 1548994144
IL_00D3: BEQ.S IL_013E
IL_00D5: RET.
IL_00D6: LDLOC.0
IL_00D7: LDC.I4 1725885116
IL_00DC: BGT.S IL_00EF
IL_00DE: LDLOC.0
IL_00DF: LDC.I4 1687544575
IL_00E4: BEQ.S IL_0162
IL_00E6: LDLOC.0.
IL_00E7: LDC.I4 1725885116
IL_00EC: BEQ.S IL_014A
IL_00EE: Ret.
IL_00EF: LDLOC.0.
IL_00F0: LDC.I4 1732096473
IL_00F5: BEQ.S IL_010E
IL_00F7: LDLOC.0.
IL_00F8: LDC.I4 1854092737
IL_00FD: BEQ.S IL_0144
IL_00FF: LDLOC.0.
IL_0100: LDC.I4 1984539276
IL_0105: BEQ.S IL_0150
IL_0107: RET.

In this case, the speed of execution will be O (log n) .

Similar IF Then Else The design is performed for o (n) . This means Switch Almost always faster If then else .

All examples of IL are compiled for .NET version 4.6

Supplement for String :

For String , it works a little differently, since the transition table cannot be built, but to look for a binary search (learning each symbol) – non-optimal. In such a compiler, he considers hash of all lines, and then during execution, hees from the incoming line, and is looking for a binary search. Example:

switch (x)
{
  CASE "FF": RETURN 10;
  Case "F1": Return 11;
  Case "F2": Return 12;
  CASE "F3": RETURN 13;
  CASE "F4": RETURN 14;
  Case "F5": Return 15;
  Case "F6": Return 16;
  Case "F7": Return 17;
  Case "F8": Return 18;
  CASE "F9": RETURN 19;
  CASE "10": RETURN 20;
  CASE "11": RETURN 21;
  CASE "12": RETURN 22;
  Default:
    Return 0;
}

IL code:

il_0001: call uint32 '& lt; PrivateimplementationDetails & gt;' :: Computestringhash (String)
IL_0006: Stlooc.0
IL_0007: LDLOC.0.
IL_0008: LDC.I4 89242279
Il_000d: bgt.un.s il_0063
IL_000F: LDLOC.0.
IL_0010: LDC.I4 38909422
IL_0015: BGT.UN.S IL_003D
IL_0017: LDLOC.0.
IL_0018: LDC.I4 5354184
IL_001D: BEQ IL_0147
IL_0022: LDLOC.0.
IL_0023: LDC.I4 22131803
IL_0028: BEQ IL_0159
IL_002D: LDLOC.0.
IL_002E: LDC.I4 38909422
IL_0033: BEQ IL_011D
IL_0038: BR IL_01DA
IL_003D: LDLOC.0.
IL_003E: LDC.I4 55687041
IL_0043: BEQ IL_0132
IL_0048: LDLOC.0
IL_0049: LDC.I4 72464660
IL_004E: BEQ IL_00F3
IL_0053: LDLOC.0.
IL_0054: LDC.I4 89242279
IL_0059: BEQ IL_0108
IL_005E: BR IL_01DA
IL_0063: LDLOC.0.
IL_0064: LDC.I4 1972548895
IL_0069: BGT.UN.S IL_008B
IL_006B: LDLOC.0. 
IL_006C: LDC.I4 122797517
IL_0071: BEQ.S IL_00DE
IL_0073: LDLOC.0.
IL_0074: LDC.I4 810679896
IL_0079: BEQ.S IL_00C9
IL_007B: LDLOC.0.
IL_007C: LDC.I4 1972548895
IL_0081: BEQ IL_01A4
IL_0086: BR IL_01DA
IL_008B: LDLOC.0.
IL_008C: LDC.I4 2006104133
IL_0091: BGT.UN.S IL_00AE
IL_0093: LDLOC.0
IL_0094: LDC.I4 1989326514
IL_0099: BEQ IL_0195
IL_009E: LDLOC.0.
IL_009F: LDC.I4 2006104133
IL_00A4: BEQ IL_0186
IL_00A9: BR IL_01DA
IL_00AE: LDLOC.0.
IL_00AF: LDC.I4 -28201054
IL_00B4: BEQ IL_0168
IL_00B9: LDLOC.0.
IL_00BA: LDC.I4 -11423435
IL_00BF: BEQ IL_0177
IL_00C4: BR IL_01DA

After that, there is a comparison by the System.String :: OP_EQUALITY method (since the hash can stamp and from different lines). This mechanism is not a hash table, since in a hash table access speed to the O (1) element, and here it is simply a binary search for O (log n)

I tried to create a very large switch 60 lines, but nothing has changed.


Answer 3, Authority 25%

You specify the wrong question.

If your task is to speed up your program, then the solution of this task will never “replace the switch to the sequence of IFs” or vice versa. The acceleration of the program is carried out at the level of algorithms used and data structures.

The fact that one or another option in certain conditions, on a particular version of the compiler is performed on several nanoseconds faster, the byte of text has been spent on it.

First, you must remember that your main task is not to win 10 processor clocks (the unfortunate context switching is much more!), And make your program understandable. Therefore, you should use Switch where it adds readability to the code, where it matches what exactly you want to say this code. And use if where it better reflects your thought.

For example, if you are satisfied with the enum ‘values, then most often you need Switch . And if you really check several conditions, especially with long computing, then it may be better than a chain if ov.

Well, and secondly, the fact that on the same version of the compiler is one of the methods of expression of the same idea compile in a faster code than another method – the thing is temporary and transient. Remember that in C++, at first, it was recommended to return the values ​​by reference for the speed, and then came the trend “WANT SPEED? Pass by Value! “, and for sure it changed now again.

Since the code has the same meaning, in any of its options sooner or later it will be compiled in the same thing. JIT compiler C # Showness does not generate the same object code for these two cases, but C++ compilers already know how to .

So, which of the implementations rather, and which slower is not an absolute concept.


You do not have to sacrifitimize the code for the sake of momentary meager benefit. Write not “as rather”, but “as more correct.” The costs of supporting a poorly written code incomparably more benefits from microoptimizations.

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions