你能告诉我这个 C“函数宏”是否有什么问题以及可能出什么问题吗?
#define foo(P,I,X) do { (P)[I] = X; } while(0)
我的目标是foo
其行为与以下函数 foofunc
完全相同对于任何 POD 数据类型 T
(即 int
、 float*
、 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/