为什么在宏中使用明显无意义的 do-while 和 if-else 语句?

2024-01-12

在许多 C/C++ 宏中,我看到宏的代码被包裹在看似毫无意义的内容中。do while环形。以下是示例。

#define FOO(X) do { f(X); g(X); } while (0)
#define FOO(X) if (1) { f(X); g(X); } else

我看不到什么do while是在做。为什么不直接写这个呢?

#define FOO(X) f(X); g(X)

The do ... while and if ... else有没有办法做到这一点 宏后面的分号总是表示相同的意思。就说你吧 有类似你的第二个宏的东西。

#define BAR(X) f(x); g(x)

现在如果你要使用BAR(X); in an if ... else语句,如果 if 语句的主体没有包含在大括号中,您会得到一个糟糕的惊喜。

if (corge)
  BAR(corge);
else
  gralt();

上面的代码将扩展为

if (corge)
  f(corge); g(corge);
else
  gralt();

这在语法上是不正确的,因为 else 不再与 if 相关联。在宏中将内容括在大括号中没有帮助,因为大括号后面的分号在语法上是不正确的。

if (corge)
  {f(corge); g(corge);};
else
  gralt();

有两种方法可以解决该问题。第一种是使用逗号对宏内的语句进行排序,而不剥夺其像表达式一样的功能。

#define BAR(X) f(X), g(X)

以上版本吧BAR将上面的代码扩展为下面的代码,这在语法上是正确的。

if (corge)
  f(corge), g(corge);
else
  gralt();

这不起作用,如果不是f(X)您有更复杂的代码体,需要放在自己的块中,例如声明局部变量。在最一般的情况下,解决方案是使用类似do ... while使宏成为带有分号的单个语句,不会造成混淆。

#define BAR(X) do { \
  int i = f(X); \
  if (i > 4) g(i); \
} while (0)

你不必使用do ... while,你可以用以下材料烹饪一些东西if ... else同样,虽然当if ... else在一个内部扩展if ... else它导致“悬空的其他 http://en.wikipedia.org/wiki/Dangling_else”,这可能会使现有的悬空 else 问题更难找到,如以下代码所示。

if (corge)
  if (1) { f(corge); g(corge); } else;
else
  gralt();

重点是在悬空分号错误的情况下用完分号。当然,此时可以(并且可能应该)争论说最好声明BAR作为实际函数,而不是宏。

综上所述,do ... while是为了解决 C 预处理器的缺点。当那些 C 风格指南告诉您放弃 C 预处理器时,他们担心的是这种事情。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在宏中使用明显无意义的 do-while 和 if-else 语句? 的相关文章

  • C++:头文件中全局函数的多重定义错误

    该函数是全局的 在头文件中定义 暂时地我想把它留在那里 头文件还构成一个具有内联函数的特定类 其中一个函数调用this全局函数 源文件不包含任何有问题的全局函数 有关错误原因的任何提示吗 如果有人感兴趣的话我可以发布代码 mainwindo
  • Dapper 强类型查询返回默认对象值

    刚刚开始使用 Dapper 并喜欢它 我遇到了问题 它返回正确数量的对象 但它们的属性都有默认值 using var dbConnection Connection await dbConnection OpenAsync const st
  • 实体框架中的重复键异常?

    我试图捕获当我将具有给定用户名的现有用户插入数据库时 引发的异常 正如标题所说 我正在使用 EF 当我尝试将用户插入数据库时 引发的唯一异常是 UpdateException 如何提取此异常以识别其是否是重复异常或其他异常 catch Up
  • ProtoBuf-net AsReference 需要 Activator.CreateInstance 中的公共构造函数吗?

    在我的两门课程中 看起来像这样 最少 using System using System Collections Generic using System Collections using System ComponentModel us
  • 在 MVC 类上创建主键字段

    我是 MVC 和 C 新手 我只是偶然发现它并发现它很有趣 我遇到了一个不允许我继续的问题 这是我的代码 using System using System Collections Generic using System Linq usi
  • 可选参数“必须是编译时常量”

    我有一个类分为两个部分文件 如下所示 public partial class PersonRepository BaseRepository
  • 为什么 LinkedList 通常比 List 慢?

    我开始在我的一些 C 算法中使用一些 LinkedList 而不是列表 希望能够加快速度 然而 我注意到他们只是感觉更慢 像任何优秀的开发人员一样 我认为我应该尽职调查并验证我的感受 所以我决定对一些简单的循环进行基准测试 我认为用一些随机
  • 将语句插入 SQL Server 数据库

    最近几天我试图找到这个错误 但没有成功 我正在尝试在数据库中插入一个新行 一切都很顺利 没有错误 也没有程序崩溃 My INSERT声明如下 INSERT INTO Polozaj Znesek Uporabnik Cas Kupec Po
  • CMake 警告:无法为目标生成安全的链接器搜索路径

    在为 pcl 项目运行 CMake 时 我收到一条警告消息 Configuring done CMake Warning at CMakeLists txt 12 add executable Cannot generate a safe
  • C++ 模板参数类型推断

    我有一个这样的C 模板 template
  • C++ 析构函数:何时释放内存?

    如果我删除一个导致其析构函数被调用的对象 那么内存是在析构函数完成函数中的任何操作之前还是之后被释放 仅当最小派生类子对象被销毁后才会释放内存 所以如果你有 class Base class Derived public Base publ
  • 在 C++ 中处理音频缓冲区时,如何执行从 float -> double -> float 的转换

    我目前正在开发一个应用程序 其中音频样本帧在以下回调中进行处理 void Eav07AudioProcessor processBlock AudioSampleBuffer buffer for int channel 0 channel
  • 使用对象列表构建树

    我有一个带有属性 id 和parent id 的对象列表 我想建造一棵树来连接那些孩子和父母 1 个父对象可以有多个子对象 并且有一个对象将成为所有对象的祖先 实现该功能最快的算法是什么 我使用 C 作为编程语言 但其他语言也可以 像这样的
  • 为什么 GCC 6.3 在没有显式 C++11 支持的情况下编译此 Braced-Init-List 代码?

    我有一个问题大括号括起来的列表的不同含义 https stackoverflow com q 37682392 2642059 我知道C 03不支持C 11initializer list 然而 即使没有 std c 11编译器标志 gcc
  • IEnumerable.比带中断的 for 循环更快吗?

    我们的代码打开表单时遇到了一些缓慢的情况 这可能是由于for循环与break这需要很长时间才能执行 我把它切换到IEnumerable Any 并看到表格很快打开 我现在试图弄清楚是否单独进行此更改会提高性能 或者是否正在访问Product
  • fscanf 和 EOF 中的否定扫描集

    我的文件中有一个以逗号分隔的字符串列表 姓名 1 姓名 2 姓名 3 我想跳过所有逗号来阅读这些名字 我写了以下循环 while true if fscanf file my string 1 break 然而 它总是比预期多执行一次 给定
  • 使 C# 编译器相信执行将在成员返回后停止

    我认为目前这是不可能的 或者这是否是一个好主意 但这是我刚才正在考虑的事情 我使用 MSTest 对我的 C 项目进行单元测试 在我的一项测试中 我执行以下操作 MyClass instance try instance getValue
  • C 中的静态和动态绑定(严格来说是 C,而不是 C++)是什么?

    我最初对发布这个问题感到担忧 以免它重复 但即使在谷歌搜索了许多关键字之后 我在 StackOverflow 上找不到任何解释 C 的静态和动态绑定的链接 尽管有 C 的问题和答案 但是都涉及classes以及显然不适合 C 的东西 Sta
  • 网页执行回发时如何停止在注册表单上?

    我正在做我的最后一年的项目 其中 我在一页上有登录和注册表单 WebForm 当用户点击锚点时Sign Up下拉菜单ddlType 隐藏 和文本框 txtCustName txtEmail and txtConfirmPassword 显示
  • XmlDocument Save 使文件保持打开状态

    我有一个简单的 C 函数 可以创建一个基本的 XML 文件并保存 private void CreateXMlFile string Filename string Name string Company XmlDocument doc n

随机推荐

  • Uiautomatorviewer SWT 异常

    由于 StackExchange 建议我不要寻求帮助或澄清以前存在的帖子 https stackoverflow com questions 48128648 uiautomatorviewer is not working throwin
  • 多线程问题

    我正在使用计时器来重置用作警告框的标签 基本上 如果用户做了某件事 更具体地说 出了问题 例如 他使用了程序无法识别的单词 这会尽早捕获出现的问题并将发生的情况返回给他 以便他可以更改输入 重置会在 5 秒后清空标签 以防止他看到类似 请不
  • 使用 mget() 将 data.table 与 rbindlist() 连接时出现意外错误消息

    准备的同时这个答案 https stackoverflow com a 47670107 3817004 我收到错误消息 错误 找不到 spine hlfs 的值 从跑步 setDT giraffe rbindlist mget df na
  • Android 标记自定义信息窗口

    我正在使用谷歌地图V2 我需要展示ListView 风俗ListView带图像 自定义InfoWindow 我尝试过并且只在以下方面取得了成功View 问题是我无法得到listItemClick event googleMap setInf
  • 当函数属于必须解析的类时,如何向 IServiceCollection 注册委托或函数?

    我正在使用 Microsoft Extensions DependencyInjection 中的 IServiceCollection IServiceProvider 我想将委托注入到一个类中 public delegate Valid
  • Java 将表面分割成小方块

    我想知道是否有任何算法可以执行以下操作 给定一个特定的表面 它将其分成相同大小的更小的矩形 像这个示例图一样 灰色区域是表面 红色方块是分区本身 我在想是否有一种优化的方法来做到这一点 一个非常糟糕的方法是在所有像素中进行 for 循环 并
  • 将日期格式更改为 ddth mmm,yyyy

    我正在网络表单上打印一些日期 目前我的日期格式是dd mmm yyyy hh mm 如何将日期格式更改为ddth mmm yyyy for例子2016年5月17日 hh mm 这是我的代码 lastlogin DateTime Parse
  • /usr/bin/ld: 找不到 -lpthreads

    我正在 Fedora 22 上编译 NVIDIA Caffe 工具 但遇到问题需要查找lpthread图书馆 Determining if the pthread create exist failed with the following
  • 如何更改R图表中的默认字体大小

    我正在使用 R 包 cooccurr 无法弄清楚如何更改关联图形中的字体大小 par 方法似乎不起作用 这是包中给出的示例 data finches cooccur finches lt cooccur mat finches type s
  • 模块模式与匿名构造函数的实例

    于是就有了这个所谓的模块模式用于创建具有私有成员的单例 var foo function var foo private return foo function console log foo bar public 还有这个方法是我自己找到
  • 如何使用 click 来解析字符串中的参数?

    假设我有一个包含参数和选项的字符串列表 其中argparse 我可以使用以下方法解析这个列表parse args将函数转化为对象 如下 import argparse extra params sum 7 1 42 parser argpa
  • 如果中断 Git 推送会发生什么?

    我运行了以下命令 git push u origin master 推送 非常大 文件很多 所以上传需要时间 中途我发现我忘记添加几个文件 所以我做了 Ctrl C 在终端 中断 Git 然后做完之后git add 我又承诺了 然后又推了
  • DDD - 如何设计不同限界上下文之间的关联

    我已经设置了一个正在使用 ORM 填充的域项目 该域包含不同的聚合 每个聚合都有自己的根对象 我的问题是应该如何处理跨越聚合边界的属性 这些属性是否应该简单地忽略边界 以便有界上下文 A 中的域对象可以引用上下文 B 中的对象 或者 是否应
  • 如何检查一次 UserDefaults 是否为空

    我的应用程序计算日期和 NSDate 之间的天数 当我发布它时 用户只能保存一个日期 一个标题和一张背景图像 现在我有一个 UICollectionView 可以选择保存多个日期 并且它将通过将日期 标题和图像字符串附加到各自的数组来创建一
  • 分叉进程的执行顺序

    我知道还有另一个同名的线程 但这实际上是一个不同的问题 当一个进程多次分叉时 父进程是否先于子进程完成执行 反之亦然 同时 这是一个例子 假设我有一个 for 循环 将 1 个父进程分叉为 4 个子进程 在 for 循环结束时 我希望父进程
  • 使用 Json.net 反序列化具有接口值的复杂嵌套字典类型

    我在尝试使用 Json net 反序列化具有接口值的相当复杂的嵌套字典类型时遇到问题 代码位于此处 https dotnetfiddle net JSoAug https dotnetfiddle net JSoAug 有问题的类型是 pu
  • python 我可以向 os.listdir 提供用户名和密码吗?

    Python 3 4 Django 1 7 Windows Apache 2 4 12 我试图列出 Windows 共享驱动器上的所有文件 仅限某些用户 然后将几个文件写入共享驱动器 我正在使用 os listdir 来执行此操作 如果我只
  • 如何使用 Selenium webdriver 在 Capybara 中打开新窗口?

    我找到了一段代码 page driver browser switch to window 这显然是切换到已经打开的窗口 我们如何使用 page driver browser 对象打开一个新窗口 Thanks 我最终来到这里 即使是一个旧线
  • 没有匹配的函数调用“pthread_create”

    我正在使用 Xcode 和 C 制作一个简单的游戏 问题是下面的代码 include
  • 为什么在宏中使用明显无意义的 do-while 和 if-else 语句?

    在许多 C C 宏中 我看到宏的代码被包裹在看似毫无意义的内容中 do while环形 以下是示例 define FOO X do f X g X while 0 define FOO X if 1 f X g X else 我看不到什么d