具有"返回"的多行宏功能声明

时间:2014-10-16 17:42:00

标签: c macros

我目前正在开发一个项目,一个特定的部分需要一个多行宏功能(据我所知,常规功能在这里不起作用)。

目标是创建一个堆栈操作宏,将任意类型的数据从堆栈中拉出(作为函数调用的内部堆栈,不是高级“堆栈”数据类型)。如果它是一个函数,它看起来像这样:

type MY_MACRO_FUNC(void *ptr, type);

其中type是从堆栈中提取的数据类型。

我目前为我的平台(AVR)实现了这个功能:

#define MY_MACRO_FUNC(ptr, type) (*(type*)ptr); \
    (ptr = /* Pointer arithmetic and other stuff here */)

这允许我写一些类似的东西:

int i = MY_MACRO_FUNC(ptr, int);

正如您在实现中所看到的,这是有效的,因为指定i的语句是宏中的第一行:(*(type*)ptr)

但是,我真正喜欢的是能够在之前有一个语句,以验证ptr在任何内容被破坏之前是一个有效的指针。但是,这会导致宏扩展,int i =指向指针检查。有没有办法在标准C中解决这个问题?谢谢你的帮助!

2 个答案:

答案 0 :(得分:2)

这非常讨厌:

#define MY_MACRO_FUNC(ptr, type) (*(type*)ptr); \
    (ptr = /* Pointer arithmetic and other stuff here */)

在某些看似偶然的情况下可能会出现意外结果,例如

if (foo) bar = MY_MACRO_FUNC(ptr, int);

考虑一下:如果foo为0,会发生什么?

我认为你最好以一种分配弹出值的形式实现它,而不是“返回”#39;它:

#define MY_POP(stack, type, v) do { \
  if (!stack) abort_abort_abort(); \
  v = *((type *) stack); \
  stack = (... compute new value ...); \
} while (0)

答案 1 :(得分:2)

作为John Bollinger points out,扩展到多个语句的宏可能会产生令人惊讶的结果。将一些语句(和声明!)作为单个语句的方法是将它们包装到一个块中(由do ... while(0)包围,例如参见here)。

但是,在这种情况下,宏应该评估某些东西,所以它必须是一个表达式(而不是一个语句)。除声明,迭代和跳转语句(forwhilegoto)之外的所有内容都可以转换为表达式:可以使用逗号运算符if对几个表达式进行排序 - else - 子句可以由条件运算符(?:)替换。

鉴于ptr的原始值可以恢复(我假设"算术和其他东西在这里"因为为了举例而添加4)

#define MY_MACRO_FUNC(ptr, type) \
    ( (ptr) && (uintptr_t)(ptr)%4 == 0 \
        ? (ptr) += 4 , *(type*)((ptr) - 4) \
        : (abort() , (type){ 0 }) )

请注意,我在ptr左右括号并围绕整个表达式,请参阅例如here获得解释。

?:的第二个和第三个操作数必须属于同一类型,因此我在(type){0}调用后包含abort。永远不会评估此表达式。你只需要一些有效的虚拟对象;在这里,type不能是函数类型。

如果您使用C89且不能使用复合文字,则可以使用(type)0,但这不允许使用结构或联合类型。


就像注释一样,Gcc有一个Statements and Declarations in Expressions扩展名。