C 中#define 的未定义行为

Undefined behaviour with #define in C

我在 C 中有一个定义,看起来像这样

#define ROW_SIZE ID_SIZE + USERNAME_SIZE + EMAIL_SIZE

计算结果为 293 然后我这样做

uint32_t num_rows = pager->file_length / ROW_SIZE;

pager->file_length肯定是0
num_rows 的结果是 289。甚至 0 / ROW_SIZE 的计算结果也是 289。

为什么表达式的答案是错误的?

宏扩展是基于令牌的替换。也就是说,

pager->file_length / ROW_SIZE

扩展到

pager->file_length / ID_SIZE + USERNAME_SIZE + EMAIL_SIZE

我相信你同意以上不一定为零,特别是如果 USERNAME_SIZEEMAIL_SIZE 不为零。

要解决这个问题,请在宏定义中的表达式两边加上括号:

#define ROW_SIZE (ID_SIZE + USERNAME_SIZE + EMAIL_SIZE)

发生的事情是

uint32_t num_rows = pager->file_length / ROW_SIZE;

扩展为

uint32_t num_rows = pager->file_length / ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;

所以 num_rows 的计算结果为 0 + ID_SIZE + USERNAME_SIZE + EMAIL_SIZE,它不是零。考虑在您的定义中添加括号:

#define ROW_SIZE (ID_SIZE + USERNAME_SIZE + EMAIL_SIZE)

您必须记住,预处理器宏在源代码中基本上是查询替换的。

如果你有,例如

uint32_t num_rows = pager->file_length / ROW_SIZE;

预处理后编译器看到的是

uint32_t num_rows = pager->file_length / ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;

由于正常 operator precedence 等于

uint32_t num_rows = (pager->file_length / ID_SIZE) + USERNAME_SIZE + EMAIL_SIZE;

这当然不是您所期望或想要的。因此,在宏中始终使用额外的括号很重要,如

#define ROW_SIZE (ID_SIZE + USERNAME_SIZE + EMAIL_SIZE)

应该这样写:

#define ROW_SIZE (ID_SIZE + USERNAME_SIZE + EMAIL_SIZE)