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.
", 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
代码测试完成!
这个代码应该不难理解了,具体可以实际上机测试体验下。
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
" , argc_test);
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语言还有这个操作,难以想象,具体的思想可以看原版英文。平时使用还是老老实实的按规范写代码,毕竟项目是需要维护的,而不是秀技巧的。