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語言還有這個操作,難以想象,具體的思想可以看原版英文。平時使用還是老老實實的按規范寫代碼,畢竟項目是需要維護的,而不是秀技巧的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM