代码逆向(四)——switch-case识别技巧初探

合集下载

switchcase语句的用法c语言

switchcase语句的用法c语言

switch case语句的用法(C语言)1.简介在C语言中,sw it ch c as e语句是一种多分支条件语句,用于根据给定的表达式的值选择不同的执行路径。

它可以有效地替代多个i f-el se 语句的使用,使代码更加简洁和可读性更高。

本文将介绍s wit c hc as e 语句的语法和常见用法。

2.语法s w it ch ca se语句的基本语法如下:s w it ch(表达式){c a se值1://执行代码块1b r ea k;c a se值2://执行代码块2b r ea k;...c a se值n://执行代码块nb r ea k;d e fa ul t://如果表达式的值与任何c as e都不匹配,则执行默认代码块}-表达式:s wi tc h关键词后面的表达式,它的值将与每个ca s e的值进行比较。

-c as e:每个ca se后面跟着一个常量值或者表达式,表示待匹配的情况。

-执行代码块:每个c a se后面的代码块将在匹配到相应的值时执行。

-b re ak:用于跳出s w it ch语句,防止继续执行其他ca se的代码块。

-d ef au lt:当表达式的值与任何ca se都不匹配时,执行de f au lt后面的代码块。

3.示例以下是一个使用s wit c hc as e的简单示例:#i nc lu de<s td io.h>i n tm ai n(){i n tn um;p r in tf("请输入一个数字:");s c an f("%d",&nu m);s w it ch(n um){c a se1:p r in tf("输入的数字是1\n");b r ea k;c a se2:p r in tf("输入的数字是2\n");b r ea k;p r in tf("输入的数字是3\n");b r ea k;d e fa ul t:p r in tf("输入的数字不是1、2或3\n");b r ea k;}r e tu rn0;}在上述示例中,用户输入一个数字,程序将根据输入的值匹配相应的c a se,并输出相应的结果。

java swtich case语句

java swtich case语句

Java中的switch case语句是一种常见的控制流语句,用于根据表达式的值选择性地执行不同的代码块。

在本文中,我将深入探讨switch case语句的使用、特点和优缺点,以帮助您更全面地理解这一主题。

1. switch case语句的基本语法和特点在Java中,switch case语句通常用于多种可能情况的条件判断。

其基本语法如下:```javaswitch (expression) {case value1:// 在expression等于value1时执行的代码块break;case value2:// 在expression等于value2时执行的代码块break;// 其他casedefault:// 默认情况下执行的代码块}```在这个语法中,表达式(expression)的值将与每个case子句中的值进行比较,如果匹配则执行相应的代码块。

如果没有任何一个case子句匹配,那么将执行default子句中的代码块。

2. switch case语句的使用场景switch case语句适用于对具体数值或枚举类型进行条件判断的情况。

在一些情况下,使用switch case语句能使代码更加清晰和简洁。

当需要对一组固定的数值进行不同的处理时,使用switch case语句通常会比使用多个if else语句更为高效。

3. switch case语句的优点相比于if else语句,switch case语句的代码结构更加清晰,易于阅读和维护。

对于一些特定的场景,switch case语句的执行效率也可能更高,因为一旦条件匹配就可以直接执行相应的代码块,而不需要逐个判断每个条件。

4. switch case语句的缺点然而,switch case语句也存在一些缺点。

switch case语句只能用于确定的数值或枚举类型,无法处理范围或其他逻辑条件的判断。

如果不小心漏写break语句,可能会导致意外的执行结果。

switchcase语句的用法java

switchcase语句的用法java

switchcase语句的用法javaswitchcase语句是Java语言中一种常用的控制流语句,用于根据不同的条件执行不同的操作。

它在处理一系列可能的选项时非常有用。

**一、switchcase语句的基本语法**```javaswitch(表达式) {case 值1:// 代码块1break;case 值2:// 代码块2break;...default:// 默认代码块}```其中,表达式可以是任何可以比较的值,如整数、字符串等。

case后面的值与表达式的比较结果相匹配时,对应的代码块会被执行,直到遇到break语句或switchcase语句结束。

如果没有任何case 匹配,则执行default代码块。

**二、使用场景**switchcase语句在处理一系列可能的选项时非常有用。

例如,当需要根据用户输入的数字选择不同的菜单选项,或者需要根据不同的天气条件采取不同的应对措施时,都可以使用switchcase语句。

**三、注意事项**1. switchcase语句只能用于基本数据类型(如int、char等)的比较,不能用于对象或类的比较。

2. 每个case后面的值必须完全匹配,不能忽略或使用通配符。

3. 在每个代码块中使用break语句可以防止程序继续执行下一个case,这是必要的,否则程序会继续执行下一个case,直到遇到break或switchcase语句结束。

4. 在使用switchcase语句时,要确保表达式的类型与case后面的值类型一致,否则比较结果可能会出现错误。

总的来说,switchcase语句是一种非常实用的控制流语句,它可以帮助我们根据不同的条件执行不同的操作,提高程序的灵活性和可读性。

java中switchcase用法

java中switchcase用法

Java中switch-case用法简介在J av a编程语言中,`sw it ch-c as e`是一种选择结构,用于根据给定表达式的值,从多个选项中选择执行不同的代码块。

`s wi tc h-c as e`提供了一种简洁、清晰的方式来处理多个条件。

基本语法`s wi tc h-ca se`语句的基本语法如下:```j av as w it ch(e xp re ss ion){c a se va lu e1://当e xp re ss io n的值等于va lu e1时执行的代码块b r ea k;c a se va lu e2://当e xp re ss io n的值等于va lu e2时执行的代码块b r ea k;c a se va lu e3://当e xp re ss io n的值等于va lu e3时执行的代码块b r ea k;//...可以有更多的c a se语句d e fa ul t://当e xp re ss io n的值不等于任何c ase值时执行的代码块}```-`ex pr es si on`是要判断的表达式,通常是整数或枚举类型。

-`ca se`后面的`v al u e`是与表达式的值进行比较的常量值。

-`br ea k`语句用于跳出`s wi tc h-ca se`结构,如果没有`br e ak`语句,程序将继续执行下一个`ca se`中的代码块。

-`de fa ul t`关键字用于指定当表达式的值没有匹配任何`cas e`时执行的代码块。

示例下面是一个简单的示例,展示了`sw it ch-c as e`的用法:```j av ap u bl ic cl as sM ai n{p u bl ic st at ic vo idm a in(S tr in g[]a rgs){i n td ay Of We ek=3;S t ri ng da y;s w it ch(d ay Of We ek){c a se1:d a y="星期一";b r ea k;c a se2:d a y="星期二";b r ea k;c a se3:d a y="星期三";b r ea k;c a se4:d a y="星期四";b r ea k;c a se5:d a y="星期五";b r ea k;c a se6:d a y="星期六";b r ea k;c a se7:d a y="星期日";b r ea k;d e fa ul t:d a y="无效的星期";}S y st em.o ut.p ri ntl n("今天是"+d ay);}}```以上示例中,根据`d a yO fW ee k`的值选择对应的代码块执行,并将结果存储在`d ay`变量中。

java case用法及搭配 -回复

java case用法及搭配 -回复

java case用法及搭配-回复Java的switch-case结构是一种流程控制语句,它允许我们基于不同的条件值对代码进行选择性执行。

本文将逐步回答关于Java的switch-case 结构的用法及搭配,并给出一些实际应用的例子。

一、switch-case的语法switch(caseExpression) {case value1:当caseExpression的值等于value1时执行的代码break;case value2:当caseExpression的值等于value2时执行的代码break;...case valueN:当caseExpression的值等于valueN时执行的代码break;default:当caseExpression的值与所有case的值均不匹配时执行的代码}在语法中,caseExpression是一个表达式,它的值将用于与每个case语句后的value进行比较。

如果caseExpression的值与某个case的value 值匹配,对应的代码段将被执行。

在每个case代码段末尾需要使用break 语句来终止当前case的执行,并跳出switch结构。

如果caseExpression 的值与所有case的值均不匹配,则会执行default代码段。

default代码段是可选的。

二、switch-case的搭配1. switch-case与int、char数据类型switch-case最常见的用法是与int和char数据类型配合使用。

例如,我们想根据输入的数字选择执行不同的功能模块,可以使用以下代码:javaint choice = 1;switch (choice) {case 1:System.out.println("执行功能1");break;case 2:System.out.println("执行功能2");break;case 3:System.out.println("执行功能3");break;default:System.out.println("无效的选择");}在上述代码中,根据变量choice的值,选择执行不同的功能代码段。

java switch case 写法 -回复

java switch case 写法 -回复

java switch case 写法-回复Java Switch Case 写法在Java编程中,switch case语句是一种用于在多个选项中选择一种执行路径的控制结构。

它基于一个表达式的值来确定要执行的代码块。

这种写法提供了一种简洁、可读性强的方式来处理多个条件。

本文将一步一步回答关于Java Switch Case写法的问题,介绍其基本语法和如何使用它。

1. 什么是Switch Case语句?Switch case语句是一种选择性执行代码块的条件控制结构。

它的工作方式类似于一系列的if-else语句,但更加简洁明了。

它的结构如下所示:switch (expression) {case value1:代码块1break;case value2:代码块2break;case value3:代码块3break;更多的case语句default:默认代码块break;}其中,`expression`是一个值或者表达式,用于确定要执行的代码块。

每个`case`关键字后面的`value`可以是常量或常量表达式,用于与`expression`的值进行比较。

如果找到了匹配的`value`,将执行对应的代码块。

如果没有找到匹配的`value`,则执行`default`后面的代码块。

2. 如何使用Switch Case语句?首先,我们需要确定一个表达式,该表达式的值将确定要执行的代码块。

这个表达式可以是任何整数类型、字符类型或枚举类型。

在执行代码块之前,我们要声明一个变量并给它赋初值。

接下来,我们需要定义一系列的case语句,每个case语句都包含一个常量值,用于与表达式的值进行比较。

当找到匹配的值时,将执行对应的代码块。

最后,我们可以选择性地包含一个`default`代码块,当没有任何匹配的值时,将执行该代码块。

这个代码块通常用于处理边界情况或其他未考虑到的情况。

3. Switch Case语句的执行流程是怎样的?当执行switch case语句时,程序会按顺序比较每个case语句中的值和表达式的值,直到找到匹配的值。

代码逆向(四)——switch-case识别技巧初探

代码逆向(四)——switch-case识别技巧初探

我们先看一段代码:int _tmain(int argc, _TCHAR* argv[]){int nNum = 2;switch (nNum){case 0:printf("nNum=0");break;case 1:printf("nNum=1");break;case 2:printf("nNum=2");break;default:printf("nNum=%d,error!",nNum);}return 0;}看完这段代码,在看完本小节的标题,有些读者可能会产生一些疑问,例如switch-case的不可达分支会被剪掉吗、switch-case分支以常量为判断条件的优化效果与if-else有多大区别、以变量为判断条件的switch-case分支优化效果与if-else分支有多大区别等等问题。

现在就让我们带着这些问题继续,让我们一一为其找到答案。

先看Debug版的反汇编代码:004133AE MOV DWORD PTR SS:[EBP-8], 2 ; 给局部变量赋值004133B5 MOV EAX, DWORD PTR SS:[EBP-8]004133B8 MOV DWORD PTR SS:[EBP-D0], EAX004133BE CMP DWORD PTR SS:[EBP-D0], 0 ; 比较是否等于0004133C5 JE SHORT Test_0.004133DB ; 如果等于0则跳到相应分支,否则继续004133C7 CMP DWORD PTR SS:[EBP-D0], 1004133CE JE SHORT Test_0.004133F4 ; 同上004133D0 CMP DWORD PTR SS:[EBP-D0], 2004133D7 JE SHORT Test_0.0041340D ; 同上004133D9 JMP SHORT Test_0.00413426 ; 都不符合则直接跳转到最后一个分支处004133DD PUSH Test_0.00415808 ; /format = "nNum=0"004133E2 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf004133E8 ADD ESP, 4004133F2 JMP SHORT Test_0.00413441004133F6 PUSH Test_0.004157B0 ; /format = "nNum=1"004133FB CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf00413401 ADD ESP, 40041340B JMP SHORT Test_0.004134410041340F PUSH Test_0.00415C18 ; /format = "nNum=2" 00413414 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf0041341A ADD ESP, 400413424 JMP SHORT Test_0.0041344100413428 MOV EAX, DWORD PTR SS:[EBP-8]0041342B PUSH EAX ; /<%d>0041342C PUSH Test_0.004157A0 ; |format = "nNum=%d,error!" 00413431 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf00413437 ADD ESP, 8通过以上反汇编代码我们可以总结出以下特点:cmp XXX,XXXjXX CASE1_TAGcmp XXX,XXXjXX CASE2_TAGcmp XXX,XXXjXX CASE3_TAG......CMP XXX,XXXJXX CASEN_TAG......JMP DEFAULTCASE1_TAG:......CASE2_TAG:......CASE3_TAG:............CASEN_TAG:............DEFAULT:......SWITCH_END_TAG:我们可以看到Debug版的反汇编指令与我们的源代码的相似度还是非常高的,都是通过开始的一连串判断,然后确定接下来走哪个Case分支。

使用C模拟ATM练习switch..case用法

使用C模拟ATM练习switch..case用法

使⽤C模拟ATM练习switch..case⽤法这个实例很简单,看⼀下就能明⽩,⾄于我已经对C⽐较熟悉了,为什么还要从这么简单的例⼦⼊⼿,这个需要再详细的说明⼀下。

由于之前学习C的时候,就是急功近利,没有仔细的去品味C中,特别是指针中的⼀些乐趣,所以我选择从基础再学习⼀遍,就这样咯。

#include <stdio.h>/*** 实现⾃动取款机界⾯的模拟来学习使⽤switch语句* switch...case语句的结构* switch(int类型变量){* case 1: //如果是1,进⾏相应的处理* ....* break;* case 2:* ....* break;* default: //可有可⽆的,表⽰如果不是上⾯的所有* ....* break;* }*/int main(void){do{printf("===================================\n");printf(": Please select the key: :\n");printf(": 1: Query :\n");printf(": 2: Credit :\n");printf(": 3: Debit :\n");printf(": 4: Return :\n");printf("===================================\n");int selected = 0;scanf("%d",&selected);switch(selected){case 1:printf("===================================\n");printf(": Your balance is $1000 :\n");printf(": Please enter any key to return :\n");printf("===================================\n");getch();break;case 2:printf("===================================\n");printf(": Please select credit money :\n");printf(": 1: $50 :\n");printf(": 2: $100 :\n");printf(": 3: return :\n");printf("===================================\n");int credit = 0;scanf("%d",&credit);switch(credit){case 1:printf("===================================\n");printf(": Your Credit money is $50 :\n");printf(": Please enter any key to return :\n");printf("===================================\n");getch();break;case 2:printf("===================================\n");printf(": Your Credit money is $100 :\n");printf(": Please enter any key to return :\n");printf("===================================\n");getch();break;case 3:break;default:printf("===================================\n");printf(": Op error!! :\n");printf(": Please enter any key to return :\n");printf("===================================\n");getch();break;}break;case 3:printf("===================================\n"); printf(": Please select debit money :\n");printf(": 1: $50 :\n");printf(": 2: $100 :\n");printf(": 3: $500 :\n");printf(": 4: $1000 :\n");printf(": 5: return :\n");printf("===================================\n"); int debit = 0;scanf("%d",&debit);switch(debit){case 1:printf("===================================\n"); printf(": Your debit money is $50 :\n");printf(": Please enter any key to return :\n");printf("===================================\n"); getch();break;case 2:printf("===================================\n"); printf(": Your debit money is $100 :\n");printf(": Please enter any key to return :\n");printf("===================================\n"); getch();break;case 3:printf("===================================\n"); printf(": Your debit money is $500 :\n");printf(": Please enter any key to return :\n");printf("===================================\n"); getch();break;case 4:printf("===================================\n"); printf(": Your debit money is $1000 :\n");printf(": Please enter any key to return :\n");printf("===================================\n"); getch();break;case 5:break;default:printf("===================================\n"); printf(": Op error!! :\n");printf(": Please enter any key to return :\n");printf("===================================\n"); getch();break;}break;case 4:printf("===================================\n"); printf(": Thank you for your using :\n");printf(": Good Bye :\n");printf("===================================\n"); return;default:return;}}while(1);return 0;}。

python中switchcase语句的用法

python中switchcase语句的用法

python中switchcase语句的用法Python中并没有内置的switch-case语句,但可以使用其他方法来模拟其功能。

在本文中,我将逐步介绍如何在Python中实现类似于switch-case语句的功能。

# 1. 使用if-elif-else语句最常用的方法是使用if-elif-else语句来模拟switch-case的功能。

该方法的基本思想是使用一系列的if-elif条件来检查变量的值,并执行相应的逻辑。

下面是一个示例:pythondef switch_case(var):if var == 1:print("执行第一种情况")elif var == 2:print("执行第二种情况")elif var == 3:print("执行第三种情况")else:print("执行默认情况")在这个例子中,我们定义了一个名为`switch_case`的函数,该函数接受一个变量`var`作为输入。

然后,我们使用一系列的if-elif条件来检查`var`的值,并执行相应的逻辑。

如果没有任何一个条件满足,将执行默认情况。

使用这种方法,我们可以很容易地实现类似于switch-case的逻辑。

但是,如果有很多不同的情况需要处理,代码可能会变得冗长和难以维护。

# 2. 使用字典映射另一种实现类似于switch-case语句的方法是使用字典映射。

基本思想是使用字典来存储每个情况对应的函数或代码块,并根据输入的变量值选择执行相应的函数或代码块。

下面是一个示例:pythondef case1():print("执行第一种情况")def case2():print("执行第二种情况")def case3():print("执行第三种情况")def default():print("执行默认情况")def switch_case(var):cases = {1: case1,2: case2,3: case3}cases.get(var, default)()在这个例子中,我们定义了几个函数`case1`,`case2`,`case3`和`default`,分别用于执行不同情况下的逻辑。

codesys的switch case语句的用法

codesys的switch case语句的用法

一、switch case语句的基本概念1.1 switch case语句是一种在编程语言中常见的条件判断结构,用于根据不同的条件执行不同的代码块。

1.2 switch case语句通常用于多个条件的判断,可以使代码更加清晰和易于维护。

1.3 switch case语句由switch关键字和多个case标签组成,每个case标签对应一个条件。

二、switch case语句的语法2.1 switch关键字后面跟着一个表达式,该表达式的值将与每个case标签进行比较。

2.2 case标签后面跟着一个常量或表达式,用于匹配switch表达式的值。

2.3 每个case标签后面可以跟着一条或多条语句,用于执行相应的代码块。

2.4 在每个case标签的代码块中可以使用break关键字来终止switch case语句的执行,否则将会继续执行下一个case标签。

三、switch case语句的用法3.1 switch case语句通常用于替代连续的if…else if…else if…else if…else结构,可以使代码更加简洁和易于阅读。

3.2 switch case语句适用于多个条件的情况,但每个条件必须是离散的值,不能是范围或区间。

3.3 在switch case语句中,如果表达式的值与任何一个case标签匹配,则从该case标签开始执行相应的代码块,直到遇到break关键字或switch case语句结束。

3.4 如果没有任何一个case标签与表达式的值匹配,则可以使用default标签来执行默认的代码块,default标签是可选的。

四、switch case语句的示例代码4.1 下面是一个简单的switch case语句的示例:```c#include <stdio.h>int m本人n() {int num = 2;switch (num) {case 1:printf("The number is 1");break;case 2:printf("The number is 2");break;case 3:printf("The number is 3");break;default:printf("The number is not 1, 2, or 3");break;}return 0;}```4.2 在上面的示例代码中,根据变量num的值执行相应的代码块,如果num的值是1,则打印"The number is 1",如果num的值是2,则打印"The number is 2",如果num的值是3,则打印"The number is 3",否则打印"The number is not 1, 2, or 3"。

c++ switch case用法举例

c++ switch case用法举例

C++中的switch case语句是一种用于多条件判断的语法结构,它可以让程序根据不同的条件执行不同的代码块。

在本文中,我们将介绍C++中switch case语句的基本用法,并通过举例来说明其具体应用。

1. switch case语句的基本语法在C++中,switch case语句的基本语法如下:```cppswitch (expression) {case value1:// 当expression的值等于value1时执行的代码块break;case value2:// 当expression的值等于value2时执行的代码块break;// 可以有多个casedefault:// 当expression的值与任何case都不匹配时执行的代码块}```其中,expression可以是一个整数、字符或枚举类型的表达式,case 后面跟着的是具体的数值或字符,default是可选的,代表expression的值与任何case都不匹配时执行的代码块。

2. switch case语句的执行流程当程序执行到switch case语句时,首先计算expression的值,然后将其与每个case后面的值进行比较,如果找到与expression的值匹配的case,就执行该case后面的代码块,直到遇到break语句或switch case语句结束。

如果找不到匹配的case,则执行default后面的代码块,如果没有default,则直接跳过switch case语句。

3. switch case语句的应用举例接下来,我们通过一个简单的例子来说明switch case语句的具体应用。

假设我们需要根据用户输入的数字来输出对应的星期几的名字,可以使用switch case语句来实现:```cpp#include <iostream>int m本人n() {int day;std::cout << "请输入一个数字(1-7):" << std::endl;std::cin >> day;switch (day) {case 1:std::cout << "星期一" << std::endl; break;case 2:std::cout << "星期二" << std::endl; break;case 3:std::cout << "星期三" << std::endl; break;case 4:std::cout << "星期四" << std::endl; break;case 5:std::cout << "星期五" << std::endl; break;case 6:std::cout << "星期六" << std::endl; break;case 7:std::cout << "星期日" << std::endl; break;default:std::cout << "输入无效" << std::endl;}return 0;}```在上面的例子中,我们首先让用户输入一个数字,然后根据这个数字使用switch case语句输出对应的星期几的名字。

python switch case用法

python switch case用法

python switch case用法摘要:1.Python简介2.switch case语句的定义3.switch case语句的语法4.switch case语句的执行过程5.switch case语句的应用实例正文:Python是一种广泛应用于多个领域的编程语言,其简洁的语法和强大的功能吸引了众多开发者。

今天我们将讨论Python中的一个重要语句——switch case语句。

switch case语句是Python中用于实现多分支选择的一种结构,它可以让程序根据不同的条件执行不同的代码块。

switch case语句的定义如下:```pythonswitch (expression):case value1:# 代码块1breakcase value2:# 代码块2break...case valueN:# 代码块Nbreakdefault:# 默认代码块```在上述定义中,`expression`是需要判断的表达式,`value1`、`value2`等是可能的取值。

当`expression`的值等于某个`case`子句中的`value`时,程序将执行对应的代码块,并在该代码块中添加`break`语句来跳出switch case语句。

如果没有匹配到任何`case`子句,程序将执行`default`子句。

switch case语句的语法如下:```pythonswitch (expression):case value1:# 代码块1case value2:# 代码块2...case valueN:# 代码块Ndefault:# 默认代码块```在执行switch case语句时,程序会从上到下依次检查每个`case`子句,如果发现匹配的值,则执行对应的代码块,并在该代码块中添加`break`语句来跳出switch case语句。

如果没有匹配到任何`case`子句,程序将执行`default`子句。

python switch case用法 -回复

python switch case用法 -回复

python switch case用法-回复Python中没有直接的switch case结构,但可以使用其他方法来模拟switch case的功能。

以下是一种常见的做法:在Python中,通常我们会使用if-elif-else语句来实现switch case的功能。

if语句根据条件的真假进行判断,如果条件为真,则执行相应的代码块;否则,执行下一个条件的判断,以此类推。

我们可以利用这种特性来模拟switch case的多分支逻辑。

首先,我们需要定义一个要判断的变量或表达式,用于决定执行哪个分支。

然后,使用if语句来判断变量的值或表达式的结果,并执行相应的代码块。

如果所有的条件都不满足,则执行else代码块。

下面是一段代码示例,演示了如何使用if-elif-else语句来模拟switch case:pythondef switch_case(argument):switcher = {0: "Case 0",1: "Case 1",2: "Case 2",3: "Case 3",}return switcher.get(argument, "Invalid case")result = switch_case(2)print(result) # 输出:Case 2result = switch_case(5)print(result) # 输出:Invalid case在上面的代码中,我们定义了一个名为`switch_case()`的函数,它接受一个参数`argument`作为要判断的值。

我们使用一个字典`switcher`来存储各个分支的返回值,其中键表示要判断的值,值表示对应分支的返回值。

通过`switcher.get(argument, "Invalid case")`,我们可以获取到`switcher`字典中键为`argument`的值,如果键不存在,则返回默认值"Invalid case"。

switchcase用法

switchcase用法

switch case是一种判断选择代码,常用于编程中。

其功能是根据不同的条件执行相应的代码块。

switch case用法如下:
1. switch用在编程中,如C语言中它经常跟Case一起使用,是一个判断选择代码。

其功能就是控制流程流转的。

2. switch语句一行接一行地执行(实际上是语句接语句)。

开始时没有代码被执行。

仅当一个case语句中的值和switch表达式的值匹配时,才开始执行语句,直到switch的程序段结束或者遇到第一个break语句为止。

如果不在case的语句段最后写上break的话,将会继续执行下一个case中的语句段。

3. 在switch语句中,条件只求值一次并用来和每个case语句比较。

在elseif语句中条件会再次求值。

4. switch语句执行时会从上到下根据括号中表达式的值作比较,当某个case语句中的表达式与此值相同时,就执行这个case语句或语句序列,直到遇到break为止。

以上就是switch case的基本用法,希望对解决您的问题有所帮助。

C语言控制流语句ifelse和switchcase

C语言控制流语句ifelse和switchcase

C语言控制流语句ifelse和switchcaseC语言控制流语句if-else和switch-caseC语言是一种通用的高级编程语言,它具有灵活的控制流语句来实现条件判断和选择结构。

本文将重点介绍C语言中的if-else语句和switch-case语句,并讨论它们的使用场景和注意事项。

一、if-else语句if-else语句是C语言中最常用的条件判断语句之一。

它的基本语法如下:```cif (条件) {// 条件为真时执行的代码块} else {// 条件为假时执行的代码块}```在if-else语句中,条件可以是任何可以获得布尔值(真或假)的表达式。

如果条件为真,将执行if后面的代码块;如果条件为假,则执行else后面的代码块。

需要注意的是,if后面的代码块可以省略,但else后面的代码块不可以省略。

下面是一个简单的示例,展示了if-else语句的基本用法:```c#include <stdio.h>int main() {int num = 5;if (num > 0) {printf("数值大于0。

\n");} else {printf("数值小于等于0。

\n");}return 0;}```在上面的示例中,如果`num`的值大于0,则会输出"数值大于0。

";否则,将输出"数值小于等于0。

"if-else语句还可以嵌套使用,以实现更复杂的条件判断逻辑。

例如:```c#include <stdio.h>int main() {int score;char grade;printf("请输入一个分数:");scanf("%d", &score);if (score >= 90) {grade = 'A';} else if (score >= 80) {grade = 'B';} else if (score >= 70) {grade = 'C';} else if (score >= 60) {grade = 'D';} else {grade = 'F';}printf("成绩等级:%c\n", grade); return 0;}```在上面的示例中,根据输入的分数,程序将输出相应的成绩等级。

代码逆向(五)——switch-case识别技巧提高

代码逆向(五)——switch-case识别技巧提高

我们前面为各位读者分别介绍了转成if-esle与利用跳转表两种优化模式,但是在最后我隐含着提出了一个问题,既如果我们的switch-case分支两个数之差大于50甚至更多的时候,那么我们此时是否仍需要利用跳转表来解决问题呢?很显然我们不能这样做,假如我们遇到如下这段代码:int _tmain(intargc, _TCHAR* argv[]){switch (argc){case 0:printf("argc=0",argc);break;case 1:printf("argc=%d",argc);break;case 6:printf("argc=%d",argc);break;case 7:printf("argc=%d",argc);break;case 199: // 注意这里!printf("argc=%d",argc);break;default:printf("nNum=%d,error!",argc);}return 0;}我们通过上面这个稍显极端的例子可以发现,如果此时编译器仍以跳转表的方式来优化的话,那么会出现什么情况?这会使得编译出来的代码具有多达788字节的冗余数据,至少会使其体积变为用Debug模式生成代码体积的2.7倍以上!通过与编译器打这么长市间的交道,我们猜也能猜得出编译器肯定不会使用这么笨的方法,由此便引出的“稀疏矩阵”。

“稀疏矩阵”这名字起的很好,正可谓阅名知意,通过名字我们就可以猜到这应该是一个用来表达稀疏数据的矩阵,正好可以用于我们刚刚所面对的这种情况。

那么我们的switch-case分支结构生么时候才会用到稀疏矩阵,而稀疏矩阵又是怎么回事呢?下面就由笔者一一为各位解答……(1、)什么时候应用稀疏矩阵由于每个编译器所使用的策略不一样,因此其“体积-效率比”权值的设定也不尽相同,笔者在这里只能告诉大家,如果使用跳转表所生成代码的体积大于使用稀疏矩阵的体积,那么一般情况下编译器就会选择使用稀疏矩阵来优化此段代码。

逆向知识第九讲,switchcase语句在汇编中表达的方式

逆向知识第九讲,switchcase语句在汇编中表达的方式

逆向知识第九讲,switchcase语句在汇编中表达的⽅式⼀⼂Switch Case语句在汇编中的第⼀种表达⽅式 (引导性跳转表)第⼀种表达⽅式⽣成条件:case 个数偏少,那么汇编中将会⽣成引导性的跳转表,会做出 if else的情况(类似,但还是能分辨出来的)1.⾼级代码:// MyCode.cpp : Defines the entry point for the console application.//#include "stdafx.h"int main(int argc, char* argv[]){switch(argc){case 0:printf("case 0\n");break;case 1:printf("case 1\n");break;case 2:printf("case 2\n");break;}printf("HelloWorld\n");return 0;}2.汇编代码在Debug版本下:可以看出,⽣成的跳转表⽐较和跳转在⼀起,⽽且跳转的时候是⼀个跳转表. (注意,这⾥可能不是⽐较,只要影响标志位即可,也可能是 Dec inc add ....等等但是没有实质性的代码)注意最后⼀个跳转 JMP,当JMP的位置,或者代码中JMP的位置(代码中也就是跳转地址过去后的地⽅)都是同⼀个地址,那么则是跳转到SWITCH_END(也就是switch case 语句块结束)注意这⾥是代码逻辑分开的.先判断逻辑,然后进⾏跳转执⾏.⽽在跳转过后的⾥⾯判断是否有JMP,有JMP的话,则代表是break如果内部没有JMP则代表没有Break,那么语法是⽀持这样写法的.3.汇编中Release版本Release版本其实是⼀样的.只不过需要注意的是,它有代码外提的情况下.因为我们每⼀个case⾥⾯都有打印输出函数,⽽且其参数都是⼀样的,所以跳转过来之后,⾥⾯只需要PUSH即可.Switch case完毕之后则会调⽤printf打印.4.扩展知识(Default在case上⾯,或者中间)4.1直接伪代码: case 0 ... break;default .... breakcase 2 ....break4.2汇编代码 Debugdebug版本不⽤说,直接JMP位置到default位置.4.3.Release版本下.对于Release版本,有的时候可能直接变为Default语句有的时候会变成JNZ执⾏.这个时候JNZ下⾯要还原成原来的CASE语句第⼀变化的还原⼿法第⼀变化还原挺简单的1.遇到cmp⽐较的, 和谁⽐较,那么跳转的地址变为对应的Case即可.注意,你点击地址过去之后则是Case语句的代码,但是要注意是否代码⾥⾯有JMP(没有则没有break)2.有的时候不是CMP, 有的时候是 dec Reg32,这个时候就要算⼀下的,⽐如 dec Reg32结果是多少,则对应还原成多少,⽐如dec Reg32结果是0,那么其还原成Case0,但是还原第⼆个的时候要注意第⼀个已经Dec了⼀下,第⼆个⼜还原的Dec 所以要和第⼀个相关联才可以.⼆⼂Switch Case语句在汇编中的第⼆种表达⽅式(简介寻址表)case 语句块有多个,且其中间隔不算多, 间隔的地⽅填写Default2.1⾼级代码:// MyCode.cpp : Defines the entry point for the console application.//#include "stdafx.h"int main(int argc, char* argv[]){switch(argc){case 0:printf("case 0\n");break;case 1:printf("case 1\n");break;case 2:printf("case 2\n");break;case 3:printf("case 3\n");case 5:printf("case 5\n");break;case 6:printf("case 6\n");break;case 7:printf("case 7\n");break;default:printf("default \n");break;}printf("HelloWorld\n");return 0;}2.2 Debug版本下的汇编代码表现形式⾸先这⾥有两个问题1. 为什么是JA (A是⽆符号的⾼于⽐较)2. 为什么出现了数组寻址公式.解答第⼀个问题: 是这样的,第⼆种优化⽅式它会⽣成跳转表,⽽跳转表就是在第⼆种⾥⾯出现的寻址.⽽做表的前提下就是要保证Case语句是排序好的.所以在这⾥ case语句⾸先排序好,⽽后坐标平移到0位置什么是坐标平移到0位置?⽐如我们有代码case -1case 2case 3那么此时坐表的条件就是case -1 变为case 0case 2 变为 2这样坐表之后则是从0开始,⽽⾥⾯保存的则是case的地址.这个时候只会和case最⼤值作⽐较.我们看下动态调试中是什么表现形式把.坐标平移之后,则可以建⽴⼀个表格,⽤的时候查表即可.所以我们查表的时候可以看到很多case语句的地址从0开始. 没有的则填写Default即可. ⼀般JA后⾯的地址就是Default或者Switch End地址,从表中我们也看出来了.第五项填写的是Switch End的地址.正好我们的代码中缺少的第五项没有Debug还原⼿法:Debug还原很简单,⾸先是⽐较case最⼤值,(看下是否调整了,也就是坐标平移了,如果平移了,⽐如以前有个-1,⽽case 最⼤值是3,那么会⽐较 4,因为-1 要+1其余各个的case语句也要加1)4.3Release版本下的汇编代码Release版本下也是⼀样,此时它也是会⽤ case值和最⼤值⽐较,然后去数组中寻址查找表去跳转注意: 这⾥数组寻址*4的意思是,地址是4个字节对其⽐如我们的表格中存放的是case地址00401000 case0 Address00401004 case1 Address00401008 case 2 Address⾸先会和最⼤值⽐较,没有超过,那么直接⽤case的值 *4去表中找地址即可.⽐如我们的case值是2, ⽐较是否⼤于7,然后 jA指令判断是否⾼于7,⾼于7跳转到 Default或者Switch End,不⾼于,则根据case值去表中查找跳转⽐如现在是2,那么 2* 4 = 8 + 数组⾸地址(00401000) = 401008 然后取出内容跳转,此时内容也是case2的地址.扩展思路:上⾯讲的是Switch原型知识,我们要学会扩展.⽐如如果我case中有个-1怎么办那么此时-1 +1 坐标平移到0的位置,然后其余各个的case +1那么⽐较的时候和case最⼤的值相⽐,现在最⼤的值也+1了. 所以还原的时候,最⼤值要-1,其余各个case值都要-1则可以.代码还原⽅式.第⼆种代码还原⽅式1.判断是否调整,调整了可以得出最⼩值,⽐如 add eax,2 那么得出最⼩值是-2,因为坐表要从0开始,这⾥调整则得出-2了,2.得出case最⼤值⽐较,这⾥也要看是否调整了,没有调整那么最⼤值是多少就是多少,调整的那么case最⼤值则是当前值 - 调整的值3.得出最⼩值和最⼤值之后,去地址表中寻址即可.因为是排好序的,如果没有调整,那么就是从0开始,还原的时候就是case0调整过后,那么减去调整的值即可,⽐如调整了2,那么第0项则是 0 - 2 则是case - 2 ⽐较.三⼂Switch Case语句在汇编中的第三种表达⽅式(多表联合查询)这种表达式相⽐前两种有点难理解,但是我们说过,编译器做的越多,那么我们还原的越快.第三种表达式形成的条件:当最⼤case值 - 最⼩case值的值在255直接,则使⽤第三种优化⽅式.3.1⾼级代码// MyCode.cpp : Defines the entry point for the console application.//#include "stdafx.h"int main(int argc, char* argv[]){switch(argc){case 0:printf("case 0\n");break;case 100:printf("case 100\n");break;case 200:printf("case 200\n");break;case 35:printf("case 35\n");case 45:printf("case 45\n");break;case 60:printf("case 60\n");break;case 70:printf("case 70\n");break;default:printf("default \n");break;}printf("HelloWorld\n");return 0;}3.2 Debug版本下的汇编代码此时我们可以看出有两次查表的动作下标表:这⾥我们说下第⼀个表,第⼀个表我们成为下标表下标表,⾥⾯存放的是Case排好序的值的位置,⽐如我们的02 在下表中找⼀下,则是对应45的位置. 那么此时从⾥⾯取出来做第⼆个case,去地址表中寻到case 45 的地址.下标表的作⽤,这⾥的下标表主要是⼀种优化,⼀种空间换时间的做法,这⾥的优化主要是,⽐如我们屏幕的颜⾊,⽩⾊很多,那么我就优化为,当有⽩⾊的时候,去下标表中寻找⽩⾊就和我们的下标表中的07⼀样,只要知道这个,那么都是default地址表:地址表则和第⼆种优化⼀样,存放的case的真实地址.debug还原⼿法:1.⾸先判断是否调整,调整了,可以得出最⼩case的值, (0 - 调整的值) 没调整则默认从0开始2.⽐较的时候会和最⼤case值⽐较(没有调整则最⼤case值就是本⾝)调整了(最⼤case值 - 调整后的值 = 真实的最⼤case值)3.遇到ja则后边现修改为 default或者switchend4.从下标表中寻得case当前的位置,(⽐如存放的是3,其位置在下表表中是35)那么此时代表的就是 case 35 (属于第三个case语句)5.从下标表中得出case语句的位置,(第⼏个case)以及case的值是多少(case 35)那么去地址表中寻找其case35的地址即可.3.3 Release版本下的汇编和Debug版本下相差⽆异,只不过有代码外提此时还原很好还原1.展开下表表格2.展开地址表格展开后则是上⾯的模样,第⼀个是地址表,第⼆个是下标表格.注意展开的时候可能会遇到问题1.不是我这种显⽰,没有这么整齐, 此时按键盘上的 * 键,可以设置按照数组显⽰, 设置数组⼤⼩,间隔.等等..2.没有显⽰ offset addr... 可能显⽰的直接是⼀个地址, 此时可以选择快捷键 ctrl + 0 显⽰成当前段偏移3.数据类型不对,我的是dd ⽽你们的可能解释为 db dw 等等.. 此时按键盘快捷键 d即可.可以调整数据类型还原⽅法;和Debug⼀样, (因为我没有调整所以不⽤算了,⽽且从0开始)此时先去下标表中寻找0, 这个0找的的是case语句的位置也就是第⼀条case语句是0然后在寻找在数组的那个位置, 这个位置指的是 case xxx xxx的值是多少此时我能找到0,那么去数组表中寻找0地址,改为case 0, 按n键修改修改1的值,也就是找case 第2条语句是什么在35位置寻找到1,那么此时第⼆条语句代表的case则是case 35利⽤⾥⾯的下边去地址表中寻址,则找到第⼆个地址则是case 35我们修改过后则上⾯会显⽰了.此时我们正常的还原即可.四⼂Switch Case语句在汇编中的第四种表达⽅式(⼆分优化查表,四种变化混合)第四种表达⽅式,⽣成条件,其case值之间的间隔⼤于255则会使⽤第四种表达⽅式.4.1⾼级代码:// MyCode.cpp : Defines the entry point for the console application.//#include "stdafx.h"int main(int argc, char* argv[]){switch(argc){case 0:printf("case 0\n");break;case 256:printf("case 256\n");break;case 34:printf("case 34\n");break;case 500:printf("case 500\n");break;case 510:printf("case 510\n");break;default:printf("default \n");break;}printf("HelloWorld\n");return 0;}⾸先说下如果遇到这种情况,编译器会怎么做.因为对于编译器来说,不知道你命中率⾼的那个case语句会执⾏,所以只能从中间切开会⽣成汇编代码 jg 或者 jle (⼤于或者⼩于代码 )还有中间判断相等.⽐如我们有⼀组case值0200300310320此时汇编代码会先判断是否 jz(等于,可能不是jz反正判断相等的跳转即可) 找到中间的case,所以此时还原这个值即可.不⽤管⼤于⼩于,最后的时候管.4.2Debug下的汇编代码:可以看出⼀⼤堆的判断相等的代码.还原⼿法:看到JE⽐较,那么看上⽅条件和谁⽐较(没有调整的情况下)那么还原当前地址为这个case即可.4.3Release版本下的汇编.这个是还原过后的,只需要判断相等即可,根据它的条件来判断,只不过Release版本有代码外提JNZ先修改为 Default ,此时如果进去每个case语句块中,按到的JMP的跳转地址和JNZ跳转的地址是⼀样的话,那么就是SWITCH_END 只需要还原相等即可.注意: 当我还原case 510的时候,有没有发现其上⾯还原500的时候都是减掉了,所以510的时候⼜减掉了⼀次所以此时判断是510⼤体的规模已经出来了,下⾯就是还原具体代码了,代码很简单,不还原了,看下和⾼级代码对⽐即可.看看case是否⼀样.。

switch_case,,,条件操作符和逗号操作符,循环语句

switch_case,,,条件操作符和逗号操作符,循环语句

switch_case,,,条件操作符和逗号操作符,循环语句⼀.switch-caseswitch-case语句主要⽤在多分⽀条件的环境中,在这种环境中使⽤if语句会存在烦琐且效率不⾼的弊端。

switch(expression){ case const expression1: .... case const expression2; ... default: ...}在执⾏过程中,expression的值会与每个case的值⽐较,实现switch语句的功能。

关键字case和它所关联的值被称作case标号。

每个case标号的值都必须是⼀个整形常量表达式,且不能存在两个case标号相同的情形。

除此之外,还有⼀个特殊的case标号-default标号。

如果expression的值与其中⼀个case标号相匹配,则程序将从该标号后⾯的第⼀个语句开始执⾏各个语句,直到switch结束或者遇到break 语句为⽌,如果没有发⽣与之匹配的case标号(并且也没有default标号),则程序会从switch语句后⾯的⼀条语句继续执⾏。

关于switch⼀般存在这样的误解:以为程序只会执⾏匹配的case标号相关的语句。

实际上并⾮如此,该标号只是程序会执⾏的起始点,程序会从该点执⾏,并跨越case边界继续执⾏其他语句,直到switch结束或遇到break语句为⽌。

break语句的使⽤,是switch-case语句的核⼼。

因为在⼤多数情况下,在下⼀个case标号前⾯必须加上⼀个break语句。

故意省略break是⼀种特别罕见的⽤法,因此在这种形式的代码附近,请务必添加⼀些注释,说明其运⾏逻辑。

在switch-case结构中,只能在最后⼀个case标号或default中定义内部变量。

指定这种规则是为了避免出现代码跳过变量定义和初始化的情况。

这个规则存在的原因:⼀般如果定义⼀个变量,此变量便从此定义开始有效,直到所在的语句块结束。

Java switch-case语句使用指南

Java switch-case语句使用指南

Java switch-case语句使用指南
在Java编程中,switch-case语句是一种用于选择多个代码块中的一种执行路
径的结构。

它通常用于替换复杂的多个if-else语句,让代码更加简洁和易于理解。

本文将详细介绍Java中switch-case语句的基本语法、用法和最佳实践。

基本语法
switch-case语句的基本语法如下所示:
switch (expression) {
case value1:
// 代码块1
break;
case value2:
// 代码块2
break;
...
default:
// 默认代码块
}
•expression是一个表达式,通常是一个整数、字符或枚举类型。

它的值将会被用来匹配各个case中的值。

•每个case关键字后面跟着一个常量值,如果expression的值与某个case中的常量值匹配,那么对应的代码块将被执行。

•每个case代码块的最后通常会有一个break语句,用来表示跳出switch-case结构。

•default关键字用来定义一个默认的代码块,当没有任何case匹配时,将执行default代码块。

使用示例
下面是一个简单的示例,演示了如何在Java中使用switch-case语句:
```java int day = 3; String dayName; switch(day) { case 1: dayName =。

switchcase语句的用法c语言 -回复

switchcase语句的用法c语言 -回复

switchcase语句的用法c语言-回复“switch-case”语句是C语言中的一种控制结构,用于根据不同的情况执行不同的代码块。

本文将详细介绍switch-case语句的用法,并通过例子一步一步说明。

首先,我们先来理解switch-case语句的基本语法格式:cswitch (表达式) {case 值1:代码块1;break;case 值2:代码块2;break;...default:默认代码块;break;}- `switch`后面的表达式可以是整型、字符型、枚举类型或者一个可以转换为整型的表达式。

这个表达式的值会与case后面的值进行比较。

- `case`后面可以跟一个常量值或者常量表达式。

- `break`语句用于终止当前的case块,避免执行其他case块的代码。

- `default`用于指定当没有匹配的case时执行的默认代码块。

接下来,我们通过一个例子来说明switch-case的用法。

c#include <stdio.h>int main() {int day;printf("请输入一个代表星期几的数字(1-7):");scanf("d", &day);switch (day) {case 1:printf("星期一\n");break;case 2:printf("星期二\n");break;case 3:printf("星期三\n");break;case 4:printf("星期四\n");break;case 5:printf("星期五\n");break;case 6:case 7:printf("周末\n");break;default:printf("无效的输入\n");break;}return 0;}在这个例子中,我们通过输入一个数字来代表星期几,然后根据输入的数字使用switch-case语句来输出相应的星期几或者周末。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

我们先看一段代码:int _tmain(int argc, _TCHAR* argv[]){int nNum = 2;switch (nNum){case 0:printf("nNum=0");break;case 1:printf("nNum=1");break;case 2:printf("nNum=2");break;default:printf("nNum=%d,error!",nNum);}return 0;}看完这段代码,在看完本小节的标题,有些读者可能会产生一些疑问,例如switch-case的不可达分支会被剪掉吗、switch-case分支以常量为判断条件的优化效果与if-else有多大区别、以变量为判断条件的switch-case分支优化效果与if-else分支有多大区别等等问题。

现在就让我们带着这些问题继续,让我们一一为其找到答案。

先看Debug版的反汇编代码:004133AE MOV DWORD PTR SS:[EBP-8], 2 ; 给局部变量赋值004133B5 MOV EAX, DWORD PTR SS:[EBP-8]004133B8 MOV DWORD PTR SS:[EBP-D0], EAX004133BE CMP DWORD PTR SS:[EBP-D0], 0 ; 比较是否等于0004133C5 JE SHORT Test_0.004133DB ; 如果等于0则跳到相应分支,否则继续004133C7 CMP DWORD PTR SS:[EBP-D0], 1004133CE JE SHORT Test_0.004133F4 ; 同上004133D0 CMP DWORD PTR SS:[EBP-D0], 2004133D7 JE SHORT Test_0.0041340D ; 同上004133D9 JMP SHORT Test_0.00413426 ; 都不符合则直接跳转到最后一个分支处004133DD PUSH Test_0.00415808 ; /format = "nNum=0"004133E2 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf004133E8 ADD ESP, 4004133F2 JMP SHORT Test_0.00413441004133F6 PUSH Test_0.004157B0 ; /format = "nNum=1"004133FB CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf00413401 ADD ESP, 40041340B JMP SHORT Test_0.004134410041340F PUSH Test_0.00415C18 ; /format = "nNum=2" 00413414 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf0041341A ADD ESP, 400413424 JMP SHORT Test_0.0041344100413428 MOV EAX, DWORD PTR SS:[EBP-8]0041342B PUSH EAX ; /<%d>0041342C PUSH Test_0.004157A0 ; |format = "nNum=%d,error!" 00413431 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; \printf00413437 ADD ESP, 8通过以上反汇编代码我们可以总结出以下特点:cmp XXX,XXXjXX CASE1_TAGcmp XXX,XXXjXX CASE2_TAGcmp XXX,XXXjXX CASE3_TAG......CMP XXX,XXXJXX CASEN_TAG......JMP DEFAULTCASE1_TAG:......CASE2_TAG:......CASE3_TAG:............CASEN_TAG:............DEFAULT:......SWITCH_END_TAG:我们可以看到Debug版的反汇编指令与我们的源代码的相似度还是非常高的,都是通过开始的一连串判断,然后确定接下来走哪个Case分支。

下面我们再看看Release版的反汇编代码:00401000 PUSH Test_0.004020F4 ; /format = "nNum=2"00401005 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf0040100B ADD ESP, 40040100E XOR EAX, EAX00401010 RETN瞧瞧,简单至极呀!由此可见switch-case语句与我们之前接触的if-else语句一样,不可达分支都会被编译器优化掉,那么如果如果其部分分支相同,是否仍会像if-else分之一样呢?先看源码:int _tmain(int argc, _TCHAR* argv[]){switch (argc){case 0:printf("argc=0",argc);break;case 1:printf("argc=%d",argc);break;case 2:printf("argc=%d",argc);break;default:printf("argc=%d,error!",argc);}return 0;}按照if-esle的优化逻辑,case 1 与csae 2 会指向同一处,真的是这样吗?我们直接看Release 版反汇编代码:00401000 /$>MOV ECX, DWORD PTR SS:[ESP+4]00401004 |.>MOV EAX, ECX00401006 |.>SUB EAX, 0 ; Switch (cases 0..2) 00401009 |.>JE SHORT Test_0.0040104D0040100B |.>SUB EAX, 1 ; 注意这里用的是减法0040100E |.>JE SHORT Test_0.0040103A00401010 |.>SUB EAX, 100401013 |.>JE SHORT Test_0.0040102700401015 |.>PUSH ECX ; /<%d>; Default case of switch 0040100600401016 |.>PUSH Test_0.00402104 ; |format = "argc=%d,error!"0040101B |.>CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf00401021 |.>ADD ESP, 800401024 |.>XOR EAX, EAX00401026 |.>RETN ; 执行完某一个分支后会直接返回00401027 |>>PUSH 2 ; /<%d> = 2; Case 2 of switch 0040100600401029 |.>PUSH Test_0.004020FC ; |format = "argc=%d" 0040102E |.>CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf00401034 |.>ADD ESP, 800401037 |.>XOR EAX, EAX00401039 |.>RETN0040103A |>>PUSH 1 ; /<%d> = 1; Case 1 of switch 004010060040103C |.>PUSH Test_0.004020FC ; |format = "argc=%d" 00401041 |.>CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf00401047 |.>ADD ESP, 80040104A |.>XOR EAX, EAX0040104C |.>RETN0040104D |>>PUSH 0 ; Case 0 of switch 00401006 0040104F |.>PUSH Test_0.004020F4 ; /format = "argc=0" 00401054 |.>CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf0040105A |.>ADD ESP, 80040105D |.>XOR EAX, EAX0040105F \.>RETN看来switch-case并没有将相同的分支合并,我们可以很清楚的看到它的4个分支仍都存在。

既然它的分支并没有合并,那么我们就讨论点其他的,请各位读者回头仔细观察反汇编代码的第1-9行,我们可以发现Release在条件跳转前用的不再是cmp,而是sub,很显然编译器这样优化是有其理由的,但是这个理由究竟是什么?我们通过阅读这块代码可知程序先将main函数的参数1传递给EAX,然后减0,这有点让人迷糊,我们接着看下面的那个跳转:00401009 |.>JE SHORT Test_0.0040104D让我们回顾一下汇编语言,我们应该都记得JE的跳转条件是ZF=1,因此当我们的EAX为0时,那么将其减0肯定会使ZF位置1,因此其实这就是一个变形的CMP指令,只不过这么做程程的代码体积更小、效率更高。

知道这些后,后面的优化自然就肯好理解了,现在假设我们的EAX等于2,因此按照上面代码的流程走会先将其减0,此时ZF位不变,接着下面又对其减1,此时ZF位仍然没变化,而当走到第三步时,此时EAX的值为1,又将其减1后肯定就等于0了,ZF位置为1,后面的JZ跳转生效……我们可以看到其实就是做了一连串的减法,到哪等于0后,就证明这个值原先为多少,由此可见微软的编译器还是很聪明的。

相关文档
最新文档