C宏可以包含临时变量吗?

我有一个我需要宏function的function。 该函数包含临时变量,我不记得是否有关于在宏替换中使用临时变量的规则。

long fooAlloc(struct foo *f, long size) { long i1, i2; double *data[7]; /* do something */ return 42; } 

MACRO表格:

 #define ALLOC_FOO(f, size) \ {\ long i1, i2;\ double *data[7];\ \ /* do something */ \ } 

这个可以吗? (即没有令人讨厌的副作用 – 除了通常的:不是“类型安全”等)。 顺便说一句,我知道“宏是邪恶的” – 在这种情况下我只需要使用它 – 没有多少选择。

只有两个条件,它以任何“合理”的方式运作。

  1. 宏没有return语句。 你可以使用do while技巧。

     #define macro(x) do { int y = x; func(&y); } while (0) 
  2. 你只针对GCC。

     #define min(x,y) ({ int _x = (x), _y = (y); _x < _y ? _x : _y; }) 

如果你解释为什么你必须使用一个宏(你的办公室有“宏星期一”或什么?)会有所帮助。 否则我们无法真正帮助。

首先,我强烈推荐内联函数。 宏可以做很少的东西而且他们做不到,而且他们更有可能做你期望的事情。

宏的一个陷阱,我在其他答案中没有看到,是变量名称的阴影。
假设你定义了:

 #define A(x) { int temp = x*2; printf("%d\n", temp); } 

有人用这种方式使用它:

 int temp = 3; A(temp); 

预处理后,代码为:

 int temp = 3; { int temp = temp*2; printf("%d\n", temp); } 

这不起作用,因为内部temp会影响外部。
常见的解决方案是调用变量__temp ,假设没有人会使用这个名称定义一个变量(这是一个奇怪的假设,假设你刚才这样做了)。

C宏只是(相对简单的)文本替换。

所以你可能会问的问题是:我可以在函数中创建块(也称为复合语句),如下例所示吗?

 void foo(void) { int a = 42; { int b = 42; { int c = 42; } } } 

答案是肯定的。

现在正如@DietrichEpp在他的回答中提到的那样,如果宏是一个像你的例子中的复合语句,那么用do { ... } while (0)而不仅仅是{ ... }来封装宏语句是一个好习惯{ ... } 。 下面的链接说明宏中的do { ... } while (0)试图阻止的情况:

http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html

此外,当你编写一个类似函数的宏时,总会问自己是否有这样做的真正优势,因为大多数情况下编写函数更好。

这基本上没问题,除了宏通常用do { ... } while(0)括起来(看一下这个问题的解释):

 #define ALLOC_FOO(f, size) \ do { \ long i1, i2;\ double *data[7];\ /* do something */ \ } while(0) 

此外,只要您的原始fooAlloc函数返回多long您必须更改宏以存储其他方式的结果。 或者,如果您使用GCC,您可以尝试复合语句扩展:

 #define ALLOC_FOO(f, size) \ ({ \ long i1, i2;\ double *data[7];\ /* do something */ \ result; \ }) 

最后,您应该关注扩展宏参数的可能副作用。 通常的模式是为块内的每个参数定义一个临时变量,并使用它们:

 #define ALLOC_FOO(f, size) \ ({ \ typeof(f) _f = (f);\ typeof(size) _size = (size);\ long i1, i2;\ double *data[7];\ /* do something */ \ result; \ }) 

Eldar的答案向您展示了宏编程的大部分缺陷以及一些有用的(但非标准的)gcc扩展。

如果要坚持标准,宏(用于通用性)和inline函数(用于局部变量)的组合可能很有用。

 inline long fooAlloc(void *f, size_t size) { size_t i1, i2; double *data[7]; /* do something */ return 42; } #define ALLOC_FOO(T) fooAlloc(malloc(sizeof(T)), sizeof(T)) 

在这种情况下,使用sizeof仅在编译时计算类型的表达式而不是其值,因此这不会对F计算两次。

顺便说一下,“尺寸”通常应该用size_t键入,而不是long或类似。

编辑:至于Jonathan关于inline函数的问题,我在这里写了一些关于C99 inline模型的内容。

是的,它应该在您使用块结构时起作用,并且临时变量在此块的内部范围中声明。

注意}在冗余之后的最后一个\。

他们能。 他们经常不应该。

为什么这个函数需要是一个宏? 你可以内联它吗?

如果你使用c ++使用内联,或者使用-c3使用gcc,它会为你内联所有函数。 我仍然不明白为什么你需要宏function这个function。

一个不完美的解决方案:(不适用于递归宏,例如彼此内部的多个循环)

 #define JOIN_(X,Y) X##Y #define JOIN(X,Y) JOIN_(X,Y) #define TMP JOIN(tmp,__LINE__) #define switch(x,y) int TMP = x; x=y;y=TMP int main(){ int x = 5,y=6; switch(x,y); switch(x,y); } 

运行预处理器后将成为:

 int main(){ int x=5,y=6; int tmp9 = x; x=y; y=tmp9; int tmp10 = x; x=y; y=tmp10; }