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

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

原文(有删改):https://www.cnblogs.com/CodeWorkerLiMing/p/14726960.html

前言

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

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

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

if(0)在goto语句中的应用

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

#include <stdlib.h>
long int strtol(const char *str, char **endptr, int base)

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

参数解析:

  • 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.\n", 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}\n", 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'\n", argv[2]);
    }
    else
    {
        printf ("Called unsupported mode: '%s'\n", argv[1]);
    }
 
    /* Clifford's Device */
    if (0)
    {
number_mode:
        printf ("Called with numeric argument: %d\n", 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
代码测试完成!

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

if(0)在switch中的应用

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

#include <stdio.h>
#define IF_DEF  1

#define MCASE((X),(SS)) if(0) {case X: SS }

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) %d\n" , argc_test);
        switch (argc_test - 1)
        {
            if (0) { case  0:
                num = "zero";
                printf ("==0\n");
            }
            if (0)
            {
            case  2:
                num = "two";
                printf ("==2\n");
            }
            if (0)
            {
            case  3:
                num = "three";
                printf ("==3\n");
            }
            if (0)
            {
            case  4:
                num = "four";
                printf ("==4\n");
            }
            if (0)
            {
            case  5:
                num = "five";
                printf ("==5\n");
            }
            if (0)
            {
            default:
                num = "many";
                printf ("==...\n");
            }
            printf ("Called with %s arguments.\n", num);
            break;
        case 1:
            printf ("Called with one argument.\n");
        }
#else
        printf ("no if (0)\n");
        switch (argc_test - 1)
        {
            //if (0)
            {
            case  0:
                num = "zero";
                printf ("==0\n");
            }
            //if (0)
            {
            case  2:
                num = "two";
                printf ("==2\n");
            }
            //if (0)
            {
            case  3:
                num = "three";
                printf ("==3\n");
            }
            //if (0)
            {
            case  4:
                num = "four";
                printf ("==4\n");
            }
            //if (0)
            {
            case  5:
                num = "five";
                printf ("==5\n");
            }
            //if (0)
            {
            default:
                num = "many";
                printf ("==...\n");
            }
            printf ("Called with %s arguments.\n", num);
            break;
        case 1:
            printf ("Called with one argument.\n");
        }
#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语言还有这个操作,难以想象,具体的思想可以看原版英文。平时使用还是老老实实的按规范写代码,毕竟项目是需要维护的,而不是秀技巧的。

posted @ 2021-06-15 14:11  schips  阅读(1091)  评论(0编辑  收藏  举报