• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

经典C语句:#define reg_write32(addr, val) do { (*((volatile uint32_t *)(addr)) = (uint32_t)(val)); } while(0)

#define reg_write32(addr, val) do { \
    (*((volatile uint32_t *)(addr)) = (uint32_t)(val)); \
} while(0)

这种do { ... } while(0)的宏定义写法是为了解决C语言宏的多个常见问题,主要有以下几个优点:

1. 避免分号问题

问题示例:

// 不好的写法
#define reg_write32(addr, val) (*((volatile uint32_t *)(addr)) = (uint32_t)(val))

if (condition)
    reg_write32(addr, val);  // 展开后会有语法问题
else
    // 其他代码

展开后:

if (condition)
    (*((volatile uint32_t *)(addr)) = (uint32_t)(val));;
else
    // 其他代码

注意有两个分号,这在if语句中会导致问题。

2. 避免与else的匹配问题

问题示例:

// 使用大括号的写法也有问题
#define reg_write32(addr, val) { (*((volatile uint32_t *)(addr)) = (uint32_t)(val)); }

if (condition)
    reg_write32(addr, val);
else
    // 其他代码

展开后:

if (condition)
    { (*((volatile uint32_t *)(addr)) = (uint32_t)(val)); };
else
    // 其他代码

大括号后的分号会导致else无法匹配前面的if。

3. do { ... } while(0)的优势

正确展开:

if (condition)
    do { (*((volatile uint32_t *)(addr)) = (uint32_t)(val)); } while(0);
else
    // 其他代码

这种写法的好处:

  • 必须加分号:while(0)后面的分号是必须的
  • 构成完整语句:在语法上是一个完整的语句
  • 兼容各种上下文:可以在if/else、循环等任何地方安全使用

4. 其他宏问题的避免

这个宏还通过其他方式避免了常见问题:

#define reg_write32(addr, val) do { \
    (*((volatile uint32_t *)(addr)) = (uint32_t)(val)); \
} while(0)

// 避免参数多次求值:每个参数只使用一次
// 使用括号:确保运算优先级
// volatile:防止编译器优化

5. 使用示例

// 各种使用场景都能正常工作
reg_write32(REG_ADDR, 0x1234);

if (condition)
    reg_write32(REG_ADDR, value);

for (int i = 0; i < 10; i++)
    reg_write32(addr_array[i], values[i]);

这种写法是C语言中编写复杂宏的标准最佳实践。

posted on 2025-10-03 20:13  SOC验证工程师  阅读(3)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3