• C语言——if(0)之后的语句真的不会执行吗?


    1、序

    学过c语言的都知道,通常:If(0)之后的代码是不执行的,网上也有详细的说明。

    1.1、形式:

    if (表达式) { 语句... }

    1.2、解释:

    在执行if语句时,首先会计算表达式的值,如果表达式的值为零,语句不会执行,若非零,则执行语句。由此可见if (0) 表示不执行,if (1)表示要执行。if (x)根据x的值是否为0来决定是否执行,他等价于if (x != 0)。

    if语句中的条件无论是什么最终都要转换成一个布尔值,因此,

    1.3、举个例子

    if(x)相当于if(x != 0)

    对于x为指针,相当于if(x != NULL)

    而if(1)

    因为1为整型,相当于if(1 != 0)

    1肯定不等于0,所以就相当于一定执行if里面的语句.

    而if(0)相当于if(0 != 0)

    这肯定不成立,所以一定不会执行if中的语句.

    x == 1,x != 1也是表达式,称为关系表达式,在C语言里,关系成立,表达式的值为1,不成立则为0,所以1>2的值为0,1!=2的值为1。C语言老师应该提到过,x大于2小于5不能写成 2 < x < 5,因为这货会被解释为(2 < x) < 5,无论x取多少,这个式子的值恒为1(根据刚刚说的应该能理解为什么了吧)。

    x=1也是一种表达式,叫赋值表达式,他的值就是等号右边的式子的值,也就是1。所以if(x=1)无论x原来为多少if语句都会成立,并且会将x的值改写为1,和if(x==1)有着非常大的区别(那么,if(x=0)呢?),正是x=1这个表达式是有值的,C语言才允许if(x=1)这种写法,一些语言里x=1这个式子是没有值的,只是将x赋值为1,这样写就会报错,如Java。C语言代码里出现if(x=1)一般情况下是你写错了,可能想表达的是if(x==1)。现在的编译器里,if(x=1)一般都会有警告提示你,可能写错了。

    总之,在C语言了里,像if,for,while这些语句本质上都是通过求出括号里表达式的是否为0来决定运行流程的,所以像if(scanf("%d",&a))这种代码也是可以理解了的。

    上面的文字应该不难理解,过了二级C语言的同学应该都能理解了。

    然而。有例外,近期在微信群中看到大佬们提到了Clifford's Device,由于一个比较冷门的c语言技巧,趁此学习下。

    2、主要参考资料

    1、菜鸟教程:C 库函数 – strtol() | 菜鸟教程 (runoob.com)和strtol - C++ Reference (cplusplus.com)以及C++ Shell (cpp.sh)在线运行网站

    2、Clifford's Homepage - Fun with Program Code。其主页:Claire Wolf (clifford.at),是一个大佬的主页,肯定是比较牛逼的,资料是英文的,不难看懂,看不懂可以谷歌翻译。

    这位大佬在文章也提到过Duff's Device,这个是比较出名的,他自己想出来一个switch case的代码框架(暂且如此称呼)。经过gcc编译运行,语法没有错。

    3、goto版本代码

    goto是一个关键字,可以在函数内直接跳转到某个label处再执行,在某些场合是比较适合的,linux中也有用到(linus也是大神~)贴代码之前,上一个库函数的c语言例子先热热身。

    C 库函数 - strtol()

    包含于标准库 - <stdlib.h>

    ——描述

     long int strtol(const char *str, char **endptr, int base)

     把参数 str 所指向的字符串根据给定的 base 转换为一个长整数(类型为 long int 型),base 必须介于 2 和 36(包含)之间,或者是特殊值 0。

    ——声明

    下面是 strtol() 函数的声明。

    long int strtol(const char *str, char **endptr, int base)

    ——参数

    str -- 要转换为长整数的字符串。

    endptr -- 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。

    base -- 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0。

    ——返回值

    该函数返回转换后的长整数,如果没有执行有效的转换,则返回一个零值。

    测试代码:

    /* strtol example */
    #include <stdio.h>      /* printf */
    #include <stdlib.h>     /* strtol */
    
    int main ()
    {
      char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff";
      char * pEnd;
      long int li1, li2, li3, li4;
      li1 = strtol (szNumbers,&pEnd,10);
      li2 = strtol (pEnd,&pEnd,16);
      li3 = strtol (pEnd,&pEnd,2);
      li4 = strtol (pEnd,NULL,0);
      printf ("The decimal equivalents are: %ld, %ld, %ld and %ld.
    ", li1, li2, li3, li4);
      return 0;
    }
    

      


    编译运行后:
    The decimal equivalents are: 2001, 6340800, -3624224 and 7340031.

    接下去,看看大佬的代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main (int argc, char** argv)
    {
        int num;
    
        if (argc != 3)
        {
            fprintf (stderr, "Usage: %s {BIN|OCT|DEC|HEX|STR} {ARG}
    ", argv[0]);
            return 1;
        }
    
        if (!strcmp (argv[1], "BIN") )
        {
            num = strtol (argv[2], NULL, 2);
            goto number_mode;
        }
        else if (!strcmp (argv[1], "OCT") )
        {
            num = strtol (argv[2], NULL, 8);
            goto number_mode;
        }
        else if (!strcmp (argv[1], "DEC") )
        {
            num = strtol (argv[2], NULL, 10);
            goto number_mode;
        }
        else if (!strcmp (argv[1], "HEX") )
        {
            num = strtol (argv[2], NULL, 16);
            goto number_mode;
        }
        else if (!strcmp (argv[1], "STR") )
        {
            printf ("Called with string argument: '%s'
    ", argv[2]);
        }
        else
        {
            printf ("Called unsupported mode: '%s'
    ", argv[1]);
        }
    
        /* Clifford's Device */
        if (0)
        {
    number_mode:
            printf ("Called with numeric argument: %d
    ", num);
        }
    
        return 0;
    }
    

      

     

    运行后:

    编译:
    gcc .Clifford-Device-goto.c -o .Clifford-Device-goto.exe
    无参数运行,提示报错
    .Clifford-Device-goto.exe
    Usage: Clifford-Device-goto.exe {BIN|OCT|DEC|HEX|STR} {ARG}
    带十六进制参数
     .Clifford-Device-goto.exe HEX 0x1234 
    Called with numeric argument: 4660
    0x1234的确=4660
    代码测试完成!
    

      


    这个代码应该不难理解了,具体可以实际上机测试体验下。

    4、switch版本代码

    这里使用了if(0),直接运行的效果如下:


    #include <stdio.h>
    
    
    #define IF_DEF  1
    
    //int main (int argc)
    int main (void)
    {
        char* num;
    
        int argc_test;
    
        for (int i = 0; i < 7; i++)
        {
            argc_test = i;
    #if IF_DEF == 1
            printf ("if (0)
    ");
            switch (argc_test - 1)
            {
                    if (0)
                    {
                    case  0:
                        num = "zero";
                        printf ("==0
    ");
                    }
                    if (0)
                    {
                    case  2:
                        num = "two";
                        printf ("==2
    ");
                    }
                    if (0)
                    {
                    case  3:
                        num = "three";
                        printf ("==3
    ");
                    }
                    if (0)
                    {
                    case  4:
                        num = "four";
                        printf ("==4
    ");
                    }
                    if (0)
                    {
                    case  5:
                        num = "five";
                        printf ("==5
    ");
                    }
                    if (0)
                    {
                    default:
                        num = "many";
                        printf ("==...
    ");
                    }
                    printf ("Called with %s arguments.
    ", num);
                    break;
                case 1:
                    printf ("Called with one argument.
    ");
            }
    #else
            printf ("no if (0)
    ");
            switch (argc_test - 1)
            {
                    //if (0)
                    {
                    case  0:
                        num = "zero";
                        printf ("==0
    ");
                    }
                    //if (0)
                    {
                    case  2:
                        num = "two";
                        printf ("==2
    ");
                    }
                    //if (0)
                    {
                    case  3:
                        num = "three";
                        printf ("==3
    ");
                    }
                    //if (0)
                    {
                    case  4:
                        num = "four";
                        printf ("==4
    ");
                    }
                    //if (0)
                    {
                    case  5:
                        num = "five";
                        printf ("==5
    ");
                    }
                    //if (0)
                    {
                    default:
                        num = "many";
                        printf ("==...
    ");
                    }
                    printf ("Called with %s arguments.
    ", num);
                    break;
                case 1:
                    printf ("Called with one argument.
    ");
            }
    #endif
        }
    
        return 0;
    }
    

      


    运行后:
    if (0)
    ==...
    Called with many arguments.
    if (0)
    ==0
    Called with zero arguments.
    if (0)
    Called with one argument.
    if (0)
    ==2
    Called with two arguments.
    if (0)
    ==3
    Called with three arguments.
    if (0)
    ==4
    Called with four arguments.
    if (0)
    ==5
    Called with five arguments.

    部分代码已经做了修改,便于学习。

    是不是很疑惑?为何没有break,也没有被fall through,经过咨询大佬,原来switch-case类似于goto-label,难怪其效率是高于if() {} else if()  {} else  {}结构的。另外if(0)可以防止被fall through 对吧,等同于添加了break。

    这下应该真相大白了,原来c语言还有这个操作,难以想象,具体的思想可以看原版英文。平时使用还是老老实实的按规范写代码,毕竟项目是需要维护的,而不是秀技巧的。

    近期开通了公众号,也一并告知下,

    扫描关注:

    个人公众号:嵌入式软件自留地

  • 相关阅读:
    第12组 Beta冲刺 (4/5)
    第12组 Beta冲刺 (3/5)
    代码用辅助多了 基础的读取config都忘记了
    wpf 动态添加控件 通过xmal实习 c#代码插入控件
    C#里调用非托管的Dll -z注意 net版本
    动态调用 类库
    c#时间的生成
    c# 第三方 修改版本号 MSBuildTasks, 解决 通配符不匹配问题
    c#.exe以管理员身份运行
    log4
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/14726960.html
Copyright © 2020-2023  润新知