c - 这个函数宏安全吗?

标签 c macros

你能告诉我这个 C“函数宏”是否有什么问题以及可能出什么问题吗?

#define foo(P,I,X) do { (P)[I] = X; } while(0)

我的目标是foo其行为与以下函数 foofunc 完全相同对于任何 POD 数据类型 T (即 intfloat*struct my_struct { int a,b,c; } ):

static inline void foofunc(T* p, size_t i, T x) { p[i] = x; }

例如,这是正常工作的:

int i = 0;
float p;
foo(&p,i++,42.0f);

它可以处理像 &p 这样的事情由于投入P在括号中,它确实增加 i恰好一次,因为I在宏中只出现一次,并且由于do {} while(0),它需要在行末尾有一个分号。 .

是否还有其他我不知道的情况,其中宏 foo不会像函数 foofunc 那样运行?

在 C++ 中,可以将 foounc 定义为模板,并且不需要宏。但我正在寻找一种可以在纯 C (C99) 中工作的解决方案。

最佳答案

您的宏适用于任意 X 参数这一事实取决于运算符优先级的详细信息。我建议使用括号,即使它们在这里碰巧不是必需的。

#define foo(P,I,X) do { (P)[I] = (X); } while(0)

这是一条指令,而不是表达式,因此不能在 fooofunc(P,I,X) 可能的任何地方使用它。即使foofunc返回void,它也可以用在逗号表达式中; foo 不能。但是,如果您不想冒险使用结果,则可以轻松地将 foo 定义为表达式,并强制转换为 void

#define foo(P,I,X) ((void)((P)[I] = (X)))

使用宏而不是函数,您失去的只是错误检查。例如,您可以编写 foo(3, ptr, 42) 而不是 foo(ptr, 3, 42)。在 size_t 小于 ptrdiff_t 的实现中,使用该函数可能会截断 I,但宏的行为更直观。 X 的类型可能与 P 指向的类型不同:会发生自动转换,因此实际上它是 P 的类型code> 确定哪个类型的 fooofunc 是等效的。

在重要方面,宏是安全的。使用适当的括号,如果您传递语法上合理的参数,您将获得格式良好的扩展。由于每个参数仅使用一次,因此所有副作用都会发生。无论哪种方式,参数之间的评估顺序都是未定义的。

关于c - 这个函数宏安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20793619/

相关文章:

c - C语言如何在一个字符串中插入多个字符

c++ - 是否有必要在 C++ 中调用继承类的公共(public)部分中的宏

C++ 宏将处理代码置于命名空间之外

lambda - let-over-lambda 书中的 cl-ppcre 阅读器

c - 比较两个 union 时“二进制操作数的无效操作数”

c - 将 2D 数组传递给函数时出现段错误

C预处理器: How to create a character literal?

c - 使用单个语句在 C 中启动后台线程

c - 指针失去其值+ execv 编译警告

c - 套接字的所有操作都需要检查 EINTR 吗?