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