【汇编 C】switch为什么高效率?分支语句if else与switch

【汇编 C】switch为什么高效率?分支语句if else与switch,第1张

目录

前言

什么是分支语句?

if else分支语句

        if else的几种写法

        注意事项

        底层刨析

switch分支语句

        switch语句的格式

        注意事项

        default与break的功能

        底层刨析

switch语句为什么高效?        

        实例测试

        结论 

        注意事项

总结

结语


前言

        本文章使用到的工具是vs2010,建议使用VC++6, *** 作都一样。

什么是分支语句?

        分支语句即进行一个选择,如果出现情况A则进行相应的 *** 作;如果出现情况B则进行相应的 *** 作,等等。

if else分支语句

        我们也知道if是如果的意思,那么可以根据意思理解,比如:

        if(love == true)                                // 如果love是真不是假

                printf("这是真爱。\n");            // 那么就输出这是真爱

        else                                                // 否则(如果love不是真,是假的)

                printf("假的。\n");                   // 那么就输出假的

        if else的几种写法

        1)if(条件) 语句;

        2)if(条件) { 语句;...}

        3)if(条件1) 语句1;

              else  语句2;

        4)if(条件1) { 语句1;...}

              else { 语句2;...}

        5)if(条件1) 语句1;

              else if(条件2) 语句2;

              else 语句3

        6)if(条件1) { 语句1;...}

              else if(条件2) { 语句2;...}

              else { 语句3;...}

        注意注意!!!

        上面的写法并不是所有的,也并不是!只要if写大括号、else if就必须写大括号的!!!什么时候写大括号,什么时候不写呢?只有当语句只有一条的时候才可以省略不写大括号,如果一个if条件成立之后需要做很多语句,那就必须带大括号。

        注意事项

        1、可以只写if语句不写else语句,但是不能只写else语句。

        2、else if可写可不写,如果写就必须有if语句。

        底层刨析

        测试代码:

#include 
#include 

int main()
{
    __asm mov eax,eax;            // 无用的代码,设置断点,产生汇编
    int x = 1;            
    if(x == 1)                    // 这里是判断,必须使用'==',因为'='在编程里是赋值
        printf("x = 1\n");
    else if (x > 1)
        printf("x > 1\n");
    else
        printf("x < 1\n");
    system("pause");              // 防止程序立即退出
    return 0;
}

        首先我们来看运行结果:

        没问题。

        Ctrl+alt+f7重新生成, F5运行,ALT+8调出反汇编,如下:

        我们先来看if(x==1) printf("x=1\n");对应的汇编: 

        cmp dword ptr [x],1:

                将局部变量x中的值与1进行比较。

        jne main+46h(5813d6h):

                如果前者(x)不等于后者(1)就跳转到5813d6这个地址,可以发现这个地址是else if,如果等于的话就继续往下执行

        mov esi,esp:

                备份

        push offset...:

                传递给printf函数参数。

        call dword ptr[__imp__printf()]:

                调用printf函数 

        add esp,4:

                一个参数,平栈加4

        cmp esi,esp:

                比较二者的值

        call @ILT+300:

                如果两者的值不相等,这个函数会报错,相等不会。

        jmp main+7Ch(54180Ch):

                跳转到54180C这个地址。

        上面的指令是整个if printf的流程。先判断,如果不相等就跳转到else if,如果相等就执行输出,并且到最后输出完了会跳转到整个if elseif else分支之外。

        else if(x>1) printf("x>1"); 

        else 

        以上便是if else的底层汇编,可以发现如果条件是'>'那么底层就会判断是否小于等于,以此类推,大家可以实验下。 

switch分支语句         switch语句的格式

        switch(表达式)

        {

                case 常量表达式1:

                        语句;

                        break;

                case 常量表达式2:

                        语句;

                        break;

                ...

                default:

                        语句;

                        break;

        }

        注意事项

        1、switch后边表达式的结果不能是浮点数!

        2、case后的值不能一样,并且必须是常量,一般对应switch后面表达式的各种结果

        3、default放在最后的时候可以不用写break;但是放在前面必须写

        4、default不一定写在最后面,如果写在前面必须带break;

        default与break的功能

        default就是默认的意思,可以看到,我们switch语句中有很多case,case就相当于if(x == ?)这样的。default就相当于else语句,当case中的表达式都不成立就会执行default,如下:

#include 
#include 

int main()
{
	int x = 1;
    switch(x)
    {
    case 2:            // 如果x==2
        printf("x=2\n");
        break;
    case 3:            // 如果x==3
        printf("x=3\n");
        break;
    default:           // 如果x!=2 并且 x!=3
        printf("x!=2、x!=3\n");
        break;
    }

    system("pause");
	return 0;
}

        结果:

    

        break是什么? 

        如果循环语句中假如break;那么他会跳出循环,那么当我们条件分支语句加上break;他也是会跳出的。

        为什么最后一行的不需要加break?

        因为最后一行的没有必要加,他再执行一步,分支语句就会退出了,所以没必要。

        例如(不加的情况):

#include 
#include 

int main()
{
	int x = 1;
    switch(x)
    {
    case 1:            // 如果x==1
        printf("x=1\n");

    case 3:            // 如果x==3
        printf("x=3\n");
        break;
    default:           // 如果x!=2 并且 x!=3
        printf("x!=2、x!=3\n");

    }

    system("pause");
	return 0;
}

        结果:

        我们得到两点结论:

        1、如果上面的条件成立了,但是没有写break,那么执行了语句之后还会继续往下执行不会退出分支语句

        2、当上面的条件成立了之后如果没有写break,那么继续往下执行的时候就不会再判断case了,只有等到break;才会退出,或者一直执行完。 

        底层刨析

        代码:

#include 
#include 

int main()
{
	__asm mov eax,eax;
	int x = 1;
    switch(x)
    {
    case 2:            // 如果x==1
        printf("x=2\n");
		break;
    case 3:            // 如果x==3
        printf("x=3\n");
        break;
    default:           // 如果x!=2 并且 x!=3
        printf("x!=2、x!=3\n");
    }

    system("pause");
	return 0;
}

        __asm处断点、CTRL+ALT+F7重新生成、F5调试、ALT+8反汇编:

        这里就不一步一步分析了。

 

 

        可以看到switch语句也是判断,如果等于就跳转到对应的位置,和if else语句貌似是一样的,那么为什么说switch语句高效呢? 

switch语句为什么高效?        

        首先我们需要了解一下switch语句的应用场景,我们知道游戏中一般都会有快捷键,这些快捷键的底层一般都是switch语句设计的,如果有快捷键,基本上不会只有一个快捷键。所以,如果仅仅是一两个条件,是根本看不出switch语句与if else的差距的。

        我这里使用的是vs2010,在这个编译器中,当条件达到四个时(不含default),switch语句就会开始高效,他与if else的差距也能轻易看出来了。(并不是所有场景都是switch条件达到四个才开始高效,一般这与编译器优化有关)。

        实例测试

        示例代码if else四条件:

#include 
#include 

int main()
{
    __asm mov eax,eax;    // 此处设置断点
	int x = 1;

	if(x == 1)
		printf("x=1\n");
	else if(x == 2)
		printf("x=2\n");
	else if(x == 3)
		printf("x=3\n");
	else if(x == 4)
		printf("x=4\n");
	else
		printf("x!=1、2、3、4\n");

    system("pause");
	return 0;
}

        ctrl+alt+f7重新生成、F5调试、ALT+8反汇编:

        可以看到if else语句条件多与少是没有区别的。

        示例代码switch:

#include 
#include 

int main()
{
	__asm mov eax,eax;
	int x = 1;
	switch(x)
	{
	case 1:
		printf("1\n");
		break;
	case 2:
		printf("2\n");
		break;
	case 3:
		printf("3\n");
		break;
	case 4:
		printf("4\n");
		break;
	default:
		printf("x!=1、2、3、4\n");
	}

	system("pause");
	return 0;
}

         ctrl+alt+f7重新生成、F5调试、ALT+8反汇编:

        直接看图:

        结论 

        当switch语句的条件超过一定个数时,底层会生成一张表(就是某个地址*edx+4我们查看所谓的某个地址就会看到这张表,如下

        这张表是通过算法计算生成的,里边存放着所有case的成立之后跳转的地址,所以我们不需要再判断一次跳转一次,判断一次跳转一次......我们直接可以通过这张表,跳转到对应的位置,这也就是switch语句的精妙之处。当分支特别多的时候switch语句与if else的差距就会越来越大。 

        注意事项

        这里大家可以通过demo程序测试一下,如果是case 1:、case 3:、case 7:这样分隔开的话,底层会是什么样的呢?如果是case 1:、case 10:、case 100:这样差距特别大的,那么switch底层又会怎么办呢?跟谁比?减多少?

        这样的问题很简单,写个程序测试一下一眼就能得出结论,所以我就不写了。

总结

        无论是if else或是switch都各有应用场景,如果你觉得switch高效,那么以后什么地方都用switch吗?不能这样,因为很多地方不需要判断那么多次,并且switch不能像if else那么灵活。

 

结语

        文章到这里就结束了,感谢大家观看!另外如果有错,还请一定指出;如果有听不懂,一定要问。 

        封面:

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/3002902.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-27
下一篇 2022-09-27

发表评论

登录后才能评论

评论列表(0条)

保存