我正在寻找一种将以下函数结构转换为宏的方法。 我知道,这是一个愚蠢而毫无意义的示例,但是它说明了这一点,因为我无法给出实际的源代码。
int foo(int x, int y)
{
do
{
--x;
++y;
}while(x > y);
return x * y; //note that x and y have changed values here.
}
这样我就可以在main或其他一些函数中调用该函数,如下所示:
int next_x = foo(x,y);
我似乎无法在这里获得100%正确的语法。 这是我的错误尝试:
#define FOO(x,y) \\
( \\
do \\
{ \\
--x; \\
++y; \\
}while(x < y), \\
x \\
)
最后的x的理由是,从理论上讲,我可以做到这一点
int next_x = foo(x,y);
但是相反,我收到语法错误,但不确定为什么。 任何帮助,将不胜感激。
==============================================
附加信息
我还应该注意,我还有其他相应构造的宏:
#define INIT(x,y)
(
x = //something,
y = //something
)
#define NEXT_INT(x,y) \\
( \\
INIT(x,y), \\
get_next_num(x,y) \\ //Note, this is an inline function call , not a macro.
)
#define NEXT_FLOAT(x,y,temp) \\
( \\
temp = NEXT_INT(x,y), \\
temp ? temp * 1.23456 : FLT_MIN \\
)
因此,我可以并且已经做到以下几点:
float my_flt = NEXT_FLOAT(x,y,temp);
我对宏的暗淡记忆告诉我,它们必须全部放在一行上。
这里没有很好的答案,那可能很好。否则,人们会认为这是一个好主意,并且会经常这样做。您的C编译器是否不支持内联(我认为在C99标准中支持内联)?我看到的唯一原因是创建C ++模板的宏版本。请不要。一些可怜的可持续工程师将为您签定一份合同。
避免内联函数的目的是什么?
是的,它确实支持内联。但是问题在于,在我的实际函数中,我需要保存x和y的新值,以供对该函数foo的后续调用。明显的方法是将指针传递给和y,然后仅创建常规的内联函数。但是,我不想这样做,因为Im正在开发时间紧迫的应用程序,因此我需要x和y保留在寄存器中。由于寄存器没有地址,这意味着它们必须存储在非CPU本地的内存中,然后再进行检索,从而耗尽了周期。
@audiFanatic:您假设内联函数的性能很差,但是我不清楚您是否确实在系统上看到过问题。除非您有不允许在编译器上启用优化的要求(否则编译器会产生质量很差的优化),否则您不必出于陈述的理由而将宏替换为内联函数。
@RossPresser否,您可以使用\告诉计算机"下一行仍然是marco的一部分"
C语法仅允许用逗号运算符(,)分隔表达式。 do ... while()不是表达式,而是语句,因此将其用作逗号运算符的值是错误的。
一般来说,内联函数应该比宏更可取,以执行一些内联??计算。它们更易于实现,更不易出错且更易于维护。在极少数情况下,内联函数将失败,而宏会成功。
确实没有安全的宏可以实现您的目标,但是一种解决方法是将要更新的变量作为宏参数传递。
#define FOO(x, y, result) \\
do { \\
do { \\
--x; \\
++y; \\
} while(x > y); \\
result = x * y; \\
} while(0)
如果使用的是GCC,则可以使用它们的statement-expression语法,它是C的扩展,而不是标准的C功能。语法如下:
({ statement; statement; expression; })
以上结果将是最后一个表达式。
在评论中,您表示:
I need to save the new values of x and y for subsequent calls to this function foo.. The obvious way to do this would be to pass pointers to x and y and then just make a regular, inlined function. However I do not want to do that because I'm making a time critical application and I need x and y to remain in registers.
您假设x和y不会留在寄存器中,这是一个错误的假设。这取决于编译器优化代码的能力。考虑以下:
static inline int foo (int *x, int *y) {
do {
--*x;
++*y;
} while (*x > *y);
return *x**y;
}
int main (int argc, char *argv[]) {
int x = argc+1;
int y = argc;
foo(&x, &y);
return 0;
}
使用gcc -O1编译时,结果为:
main:
.LFB14:
movl %edi, %edx
.L2:
movl %edi, %eax
addl $1, %edx
subl $1, %edi
cmpl %edx, %eax
jg .L2
movl $0, %eax
ret
.LFE14:
您会发现没有指针值取消引用,这正是您希望发生的事情。
嗯...那很有趣。我想我以为自从被告知以来,如果我有一个将数组指针作为参数的函数,我应该首先将所需的数据复制到寄存器中,然后将修改后的数据保存回该函数的末尾。 。但是查看我的.asm文件,似乎很对,尽管由于它与其他代码交织在一起很难辨认。
@audiFanatic:取决于函数是否内联。如果该函数不是内联函数,则可能会受益于从指针中复制值,然后在以后将其复制回。但是对于内联函数,大多数编译器将做正确的事情。
您不能将do/while循环用作表达式,因此需要在括号内使用一个块,如下所示:
编辑:这是一个GCC扩展,不是标准C
#define FOO(x,y) \\
({ \\
do \\
{ \\
--x; \\
++y; \\
}while(x > y); \\
x; \\
})
我的答案中的其他错误是缩进效果较差,而对于GCC,我没有意识到这一点。很好的答案Drew Mc。谢谢!
否则我们可以在" \"后留一个空格。我认为最常见的错误
那么,这可能是个问题,因为Im不使用GCC,Im为我的应用程序使用了专门的编译器。我很好奇,为什么将括号放在x;之后而不是仅放在循环周围?
这就是语法的工作原理。它更有可能显示其代码块要顺序执行,并且括号告诉编译器将最后一条语句用作表达式的结果。
这里的一个问题是多行宏在每一行的末尾都需要一个\\。
很抱歉给我带来混乱,我很快用notepad ++做了这个,我忘了原先添加它们,这是我的错。但是,不幸的是,那不是问题。