do {...} while (0) in macros

you are a C programmer, you must be familiar with macros. They are powerful and can help you ease your work if used correctly. However, if you don‘t define macros carefully, they may bite you and drive you crazy. In many C programs, you may see a special macro definition which may seem not so straightforward. Here is one example:

#define __set_task_state(tsk, state_value)          do { (tsk)->state = (state_value); } while (0)

There are many this kind of macros which uses do{...}while(0) in Linux kernels and other popular C libraries. What‘s the use of this macro? Robert Love from Google(previously worked on Linux kernel development) gives us the answer.

do{...}while(0) is the only construct in C that lets you define macros that always work the same way, so that a semicolon after your macro always has the same effect, regardless of how the macro is used (with particularly emphasis on the issue of nesting the macro in an if without curly-brackets).

For example:

#define foo(x)  bar(x); baz(x)

Later you may call:

foo(wolf);

This will be expanded to:

bar(wolf); baz(wolf);

This is the expected output. Next let‘s see if we have:

if (!feral)
    foo(wolf);

The expansion may not be what you expect. The expansion may be:

if (!feral)
    bar(wolf);
baz(wolf);

It isn‘t possible to write multistatement macros that do the right thing in all situations. You can‘t make macros behave like functions—without do/while(0).

If we redefine the macro with do{...}while(0), we will see:

#define foo(x)  do { bar(x); baz(x); } while (0)

Now, this statement is functionally equivalent to the former. The do ensures the logic inside the curly-brackets executes, the while(0) ensures that happens but once. Same as without the loop.For the above if statement, it will be :

if (!feral)
    do { bar(wolf); baz(wolf); } while (0);

Semantically, it‘s the same as:

if (!feral) {
    bar(wolf);
    baz(wolf);
}

You might rejoin, why not just wrap the macro in curly-brackets? Why also have the do/while(0) logic? For example, we define the macro with curly bracket:

#define foo(x)  { bar(x); baz(x); }

This is fine for the above if statement, but if we have below statement:

if (!feral)
    foo(wolf);
else
    bin(wolf);

The expanded code will be :

if (!feral) {
    bar(wolf);
    baz(wolf);
};
else
    bin(wolf);

This is a syntax error.

In conclusion, macros in Linux and other codebases wrap their logic in do/while(0) because it ensures the macro always behaves the same, regardless of how semicolons and curly-brackets are used in the invoking code.

时间: 2024-11-10 00:15:58

do {...} while (0) in macros的相关文章

ATL and MFC String Conversion Macros

ATL 7.0介绍了一些新的转换类和宏,为现有的宏提供了重要的改进.新的字符串转换类和名称宏的形式是:C 源类型 2[C] 目标类型[EX]其中:•源类型和目标类型描述如下表.• [C]是目标类型必须是只读的.•[EX]是缓冲器的初始大小必须被指定为一个模板参数. 源类型/目标类型  描述 A  ANSI字符串 W  Unicode字符串 T  通用字符串(如果定义了_UNICODE)则等同于W,否则等同于A OLE  OLE字符串(等同于W) 例如,从一个Unicode字符串转换为普通字符串不

Notepad++ 快捷键修改使之更符合Emacs的用户习惯

Notepad++ 快捷键修改使之更符合Emacs的用户习惯,主要是设置时会与NOTEPAD++自带的键冲突,例如ALT+F,这个优先级是高于用户自定义的快捷键,最后是通过录制宏的方式解决.使用只需要将下面的XML替换用户目录下的shortcuts.xml(C:\Users\xxx\AppData\Roaming\Notepad++)便可以了. <NotepadPlus> <InternalCommands> <Shortcut id="41001" Ct

常用MFC宏

最近我在用MFC开发一个智能家居监控平台的软件(用到了MSCOMM串口通信控件),当我通过在一个对话框类A中定义另一个对话框类B的对象访问B的public成员时,提示不可访问.后来经过多天的向朋友求救,终于在一个大神的帮助下找到了解决方案.原来在使用ActiveX控件时会产生一个DECLARE_EVENTSINK_MAP()宏,在此宏之后定义的每一个成员如果不指定一个新的存取类型都会失去其原有的属性.如果在DECLARE_EVENTSINK_MAP()宏(或者其它宏)之后定义任何一个成员,都必须

HIVE 原理

Overview HiveQL DDL statements are documented here, including: CREATE DATABASE/SCHEMA, TABLE, VIEW, FUNCTION, INDEX DROP DATABASE/SCHEMA, TABLE, VIEW, INDEX TRUNCATE TABLE ALTER DATABASE/SCHEMA, TABLE, VIEW MSCK REPAIR TABLE (or ALTER TABLE RECOVER P

CV_Assert的含义

Checks a condition at runtime and throws exception if it fails C++: CV_Assert(expr None) Parameters: expr – Expression for check. The macros CV_Assert (and CV_DbgAssert) evaluate the specified expression. If it is 0, the macros raise an error (see er

翻转错误法线

1 try 2 ( 3 fn ApplyOperation ctype oper = 4 ( 5 If (Modpanel.getcurrentObject() == $.baseobject) then oper $ 6 If Classof (Modpanel.getcurrentObject ()) == ctype then (oper $.modifiers[modPanel.getModifierIndex $ (Modpanel.getcurrentObject ())]) 7 )

Android Mokoid Open Source Project hacking

/***************************************************************************** * Android Mokoid Open Source Project hacking * * 声明: * 1. 本文主要是为了了解Android HAL工作机制,从而决定分析mokoid开源项目: * 2. 源代码URL:https://code.google.com/p/mokoid/source/checkout: * 3. 本文通

鬃嘴释怀说太多就成真不了。

子阻撞砖奏尊仔籽着 释怀说太多就成真不了. http://passport.baidu.com/?business&un=vip&un=%E5%A4%A9%E6%B0%B4%E4%B8%8A%E9%97%A8%E8%BF%99%E5%B0%8F%E5%A7%90#0 http://passport.baidu.com/?business&un=vip&un=%E7%99%BD%E9%93%B6%E4%B8%8A%E9%97%A8%E8%BF%99%E5%B0%8F%E5%A

澜星粘鼐贩逊耐盼系甭妊倏纪傲傲sdfghjk

http://passport.baidu.com/?business&un=R&un=%E5%A4%A7%E5%AE%81%E6%A1%91%E6%8B%BF%E9%80%9A%E5%B0%8F%E5%A7%90#0 http://passport.baidu.com/?business&un=R&un=%E4%B9%A1%E5%AE%81%E6%A1%91%E6%8B%BF%E9%80%9A%E5%B0%8F%E5%A7%90#0 http://passport.bai