为什么说do while(0) 妙?因为它的确就是妙,而且在linux内核中实现是相当的妙,我们来看看内核中的相关代码:

#define db_error(fmt, ...) \
    do { 					\
		 fprintf(stderr, "(error): ");  \
		 fprintf(stderr, fmt, ##__VA_ARGS__); \
        } while (0)

这只是个普通的调试信息的输出,有人便会认为,你这不是多此一举吗?去掉do while(0)不一样也实现了吗?其实不然,我们看看例子就清楚了,尽管很简单:

int main(void)
{
	while(0)
	{
	  printf("hello world\n");
	}

	do
	{
		printf("hello world1\n");
	}while(0);

	return 0 ;
}

这是一段简单到不能再简单的代码了,但还是要提一下,请看运行结果:

谁都知道第一个while(0)肯定是不会运行的,因为while()括号中的数值等于0,逻辑判定为假,即代码块中的hello world不会运行,但是do while(0)就不一样了,do while(0)即使条件不成立,也会拼了老命的去执行一次!

也就是说,为什么内核代码要这样来做,这是因为内核代码采用do{}while(0);这种结构可以保证无论在什么地方都可以正确的执行一次 ,这就是它用得最妙的地方,否则有时候调试程序的时候,单单的调试语句写了没打印其实是很正常的事情,不知道大家写代码的时候有没有遇到过,反正我是遇到过了,后来就是用这样的一种方法定位到错误点,顺利改正。





代码虽简单,但是用好用精熟练使用不一定什么时候都能想得到,越简单的东西,有时候,适用价值还是很好的!

分享以下我实现的调试输出程序,以后可以拿来当模版开发了:

#include <stdio.h>
#include <stdarg.h>
//内核代码采用do{}while(0);这种结构可以保证无论在什么地方都可以正确的执行一次
#define db_error(fmt, ...) \
    do { 					\
		 fprintf(stderr, "(error): ");  \
		 fprintf(stderr, fmt, ##__VA_ARGS__); \
		 } while (0)

#define db_msg(fmt, ...) \
    do {              				\
		 fprintf(stdout, "(msg): "); \
		 fprintf(stdout, fmt, ##__VA_ARGS__); \
	   } while (0)

#define db_warn(fmt, ...) \
    do { fprintf(stdout, "(warn): "); \
		 fprintf(stdout, fmt, ##__VA_ARGS__);  \
	   } while (0)

#define db_debug(fmt, ...) \
    do {  				   \
		fprintf(stdout, "(debug): ");  \
		fprintf(stdout, fmt, ##__VA_ARGS__);  \
	   } while (0)
int main(void)
{
	db_error("h\n");
	db_warn("e\n");
	db_debug("llo\n");
	return 0 ;
}

运行结果:

调试信息在前,很快就可以知道在什么地方打印的语句,方便DEBUG!迅速找到程序bug的定位!

C语言在linux内核中do while(0)妙用之法的更多相关文章

  1. go例子(一) 使用go语言实现linux内核中的list_head

    package list 代码 package list import ( "fmt" ) // 数据接口 type ElemType interface{} // 节点 type ...

  2. linux内核中的C语言常规算法(前提:你的编译器要支持typeof和type)

    学过C语言的伙伴都知道,曾经比较两个数,输出最大或最小的一个,或者是比较三个数,输出最大或者最小的那个,又或是两个数交换,又或是绝对值等等,其实这些算法在linux内核中通通都有实现,以下的代码是我从 ...

  3. 嵌入式C语言自我修养 01:Linux 内核中的GNU C语言语法扩展

    1.1 Linux 内核驱动中的奇怪语法 大家在看一些 GNU 开源软件,或者阅读 Linux 内核.驱动源码时会发现,在 Linux 内核源码中,有大量的 C 程序看起来“怪怪的”.说它是C语言吧, ...

  4. Linux内核中的fastcall和asmlinkage宏

    代码中看见:#define _fastcall 所以了解下fastcall -------------------------------------------------------------- ...

  5. C语言之linux内核实现最大公约数算法

    最大公约数算法,又称欧几里德算法,至今已有几千年的历史了.在我们开始学习C语言的时候最常用的算法就是辗转相除法,其实在linux内核中,内核也是使用这样的方法实现两数最大公约数的计算. 两个整数的最大 ...

  6. 调皮的程序员:Linux之父雕刻在Linux内核中的故事

    本文内容由公众号“格友”原创分享. 1.引言   (不羁的大神,连竖中指都这么帅) 因为LINUX操作系统的流行,Linus 已经成为地球人都知道的名人.虽然大家可能都听过钱钟书先生的名言:“假如你吃 ...

  7. Linux 内核中的 GCC 特性

    https://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/ GCC 和 Linux 是出色的组合.尽管它们是独立的软件,但是 Linux 完全依靠 ...

  8. linux内核中GNU C和标准C的区别

    linux内核中GNU C和标准C的区别 今天看了一下午的linux内核编程方面的内容,发现linux 内核中GNU C与标准C有一些差别,特记录如下: linux 系统上可用的C编译器是GNU C编 ...

  9. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

随机推荐

  1. SQLite 创建数据库(http://www.w3cschool.cc/sqlite/sqlite-create-database.html)

    SQLite 创建数据库 SQLite 的 sqlite3 命令被用来创建新的 SQLite 数据库.您不需要任何特殊的权限即可创建一个数据. 语法 sqlite3 命令的基本语法如下: $sqlit ...

  2. Unity插件 - MeshEditor(六) 变形动画状态机

    变形动画状态机--MeshAnimator,是针对MeshAnimation的状态管理器,有大量类似Unity animator的功能,但MeshAnimator操作会更加简便,更加直观,居家旅(zh ...

  3. Android官方推荐使用DialogFragment替换AlertDialog

    DialogFragment是在Android3.0(API level 11)中引入的,它代替了已经不建议使用的AlertDialog. DialogFragment高效地封装和管理对话框的生命周期 ...

  4. OpenCV3.0 3.1版本的改进

     摘要        OpenCV现在更新到了3.1版本,相对OpenCV2有了很大改进,其中对于硬件加速,移动开发(IOS,android)的支持成为亮点.      新版的OpenCV采用了内 ...

  5. An universal algorithm design of fixed length substring locating

         An universal algorithm design of fixed length substring locating Stringlocating is a very commo ...

  6. 【IOS 开发】Object - C 面向对象 - 类 , 对象 , 成员变量 , 成员方法

    . 一. 类定义 类定义需要实现两部分 : -- 接口部分 : 定义类的成员变量和方法, 方法是抽象的, 在头文件中定义; -- 实现部分 : 引入接口部分的头文件, 实现抽象方法; 1. 接口部分定 ...

  7. C#之FileInfo的简单操作

    和DirectoryInfo一样,FileInfo类同样是很方便的就能实现复杂的功能. 如下,我们一起来看一下一个简单的小例子吧. using System; using System.Collect ...

  8. 1021. Deepest Root (25) -并查集判树 -BFS求深度

    题目如下: A graph which is connected and acyclic can be considered a tree. The height of the tree depend ...

  9. Chapter 2 User Authentication, Authorization, and Security(8):创建映射到登录名的数据库用户

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/38944121,专题目录:http://blog.csdn.net/dba_huangzj ...

  10. TCP的ACK确认系列 — 发送状态转换机

    主要内容:TCP的ACK发送方式,以及ACK发送状态转换机的实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 TCP采用两种方式来发送ACK: ...