#define XXX do{ XXX } while(0) 为什么会有这种用法

时常会遇到一个很"奇怪的宏定义", rt.(欧西巴...思考不够深刻啊, 皮鞭, 啪啪啪)

最近又遇到这家伙了,Quora上面Love神回答了这个问题, 我也就顶礼膜拜

http://www.quora.com/What-is-the-purpose-of-using-do-while-0-in-macros

这是C语言里面宏定义的时候,不会造成歧义或副作用的一种常用技巧.

考虑一下情况

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

常规的,扩展成如下代码:

bar(wolf); baz(wolf);

这都还好,没啥问题.但是如果遇到if判断语句了,看看下面的例子.

f (!feral)
    foo(wolf);

这就扩展成了下面的形式,(⊙o⊙)看,是不是出现了你不想要粗线的情况捏?

这里if语句只能作用于第一个bar()函数,无法作用于第二个baz().但是这种方式很可能不是程序员的本意.

本意就是把foo单做一个整体嘛~

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

等价于如下形式

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

离开了 do/while(0)你就别想把宏定义玩的跟函数一样一样的~

如果使用这种技巧定义宏定义,

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

还是这个宏定义,这么用

f (!feral)
    foo(wolf);

就变成了如下形式.

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

等价于

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

你可能会想,用下面这种方式,加个{}不就解决问题了么?干嘛害的要do{} while(0)?

考虑如下情况

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

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

这就变成了

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

注意!这里使得else变成了"臭名昭著的"dangling else.

时间: 2024-10-14 03:36:10

#define XXX do{ XXX } while(0) 为什么会有这种用法的相关文章

Error Domain=ASIHTTPRequestErrorDomain Code=8 "Failed to move file from"xxx/xxx"to"xxx/xxx"

今天真的好高兴呀 我解决了一个折磨了我一周的问题,真的是激动地要哭出来了,为了这个问题,我嘴也烂了,头发抓了一地啊.虽然解决方法,最后还是展现出了“百度”的伟大,但是我还是很开心,在这里我展示一下我的战果 问题的表面就是在2G下下载zip包失败,不是每次都失败,而是只要我离开当前页面再次进入当前页面就会失败(进入requestFail),如果只是离开不进入,那么一起正常. 多么诡异呀,起初我也想通过看看进入页面后是不是进行了什么卑鄙的操作,而导致ASI罢工,可是最后我放弃了,因为任何有关ASI的

C语言中宏定义(#define)时do{}while(0)的价值(转)

C语言中宏定义(#define)时do{}while(0)的价值 最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总结了一下讨论,加上自己的理解,do{...}while(0)的价值主要体现在: 1. 增加代码的适应性 下面的宏定义没有使用do{...}while(0) #define FOO(x) foo(x); bar(x); 这样宏定义,单独调用不会出现问题,例如: FOO(100) 宏扩展后变成: 1 f

sql数据库删除表的外键约束(INSERT 语句与 FOREIGN KEY 约束"XXX"冲突。该冲突发生于数据库"XXX",表"XXX", column 'XXX)

使用如下SQL语句查询出表中外键约束名称: 1 select name 2 from sys.foreign_key_columns f join sys.objects o on f.constraint_object_id=o.object_id 3 where f.parent_object_id=object_id('表名') 执行如下SQL语句删除即可. 1 alter table 表名 drop constraint 外键约束名 sql数据库删除表的外键约束(INSERT 语句与 F

ios dyld: Library not loaded: @rpath/xxx.framework/xxx 之根本原因

碰到问题 dyld: Library not loaded: @rpath/xxx.framework/xxx Referenced from: /var/containers/Bundle/Application/0F41980D-5091-449D-AE29-5D018E3EB554/DemoOC.app/DemoOC Reason: image not found enable Always Embed Swift Standard Libraries option under Build

拒绝了对对象 'XXX' (数据库 'XXX',架构 'dbo')的 SELECT 权限

2010-04-17 23:16 在IIS里测试ASP.NET网站时会遇到这样的问题(ASP.NET+SQL2005)我自己的解决方法是这样的: 1.打开SQL2005管理界面(没有安装SQLServer2005_SSMSEE.msi的话从VS2005服务器里进去) 2.在“对象资源管理器”里,展开“数据库”下面的“安全性”,右键“登录名”弹出“新建登录名...”弹出新建登录名窗口,登录名处右边“搜索”——“高级”——“立即查找”,选择“ASPNET”,两次确定后成功添加用户“ASPNET”,下

DerivedData/xxx-fxhqtzymbwegttddoznsqpakmlvp/Build/Products/Debug-iphonesimulator/xxx.app/xxx

运行程序报错 ld: file not found: ~/Library/Developer/Xcode/DerivedData/xxx-fxhqtzymbwegttddoznsqpakmlvp/Build/Products/Debug-iphonesimulator/xxx.app/xxx clang: error: linker command failed with exit code 1 (use -v to see invocation) clean 项目后  删除DerivedDat

error: expected declaration specifiers or '...' before xxx(xxx是函数形参)

在使用带参有返回值的函数指针做参数时,编译出现下面情况 -------- error: expected declaration specifiers or '...' before 'FunType' 情形描述: a.h: typedef void (*FunType)(); void callFun(FunType p); a.c : #include "a.h" FunType myfuntype=NULL; void callFun(FunType p) { myfuntype

VUE引入模块之import xxx from 'xxx' 和 import {xxx} from 'xxx'的区别

import FunName from ‘../xxx’ export defualt function FunName() { return fetch({ url: '/article/list', method: 'get' }); } import {xxx} from ‘../xxx’ export function FunName() { return fetch({ url: '/article/list', method: 'get' }); } ES中的模块导出导入 expor

SpringBoot: Field xxx in xxx required a bean of type 'xxx' that could not be found.

SpringBoot自动注入报了如下错误 . 原因是我这个模块依赖另一个模块里面的被Spring管理的类,但是不在同一包下面, 并且启动类不是在根包下面,所以就导致了springboot启动的时候扫描不到,也就管理不到这个类,也就无法找到, 解决方案: 1.SpringBoot启动类放到包的跟包下面比如每个包都包含 cn.arebirth.xx  那就放在cn.arbeirth下面 2.设置SpringBoot扫描的包路径即可解决 SpringBoot: Field xxx in xxx req

DNS 私有域的选择:internal.xxx.com xxx.local 还是 xxx.zone?

内网 DNS,某种意义上说,很类似内网 IP 网段.但是 IP 网段的选择主要看网段的大小,而内网 DNS 的选择主要考虑的是可读性.长短等. 使用 internal.xxx.com:就是用公网域名的子域.是使用最广泛的用法,配置也简单. 但是要小心私有 DNS 服务器和公网 DNS 冲突的问题. 也有人抱怨这样的域名太长了. 使用 xxx.local/xxx.lan: 适合不直接面向用户的应用. 这样能确保不存在 DNS 冲突,但是 Chorme 在浏览器中输入 xxx.local 会默认进行