c语言 宏 循环,关于语法:在C宏内放入循环

本文探讨了如何在C语言中使用宏实现类似函数结构的循环功能,作者尝试将一个do-while循环转换为宏,并在过程中遇到了语法问题。通过讨论和示例,解释了为何不能直接将do-while循环作为表达式,并提出了使用块(braces)来包裹循环的解决方案,以解决在非GCC编译器上的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我正在寻找一种将以下函数结构转换为宏的方法。 我知道,这是一个愚蠢而毫无意义的示例,但是它说明了这一点,因为我无法给出实际的源代码。

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 ++做了这个,我忘了原先添加它们,这是我的错。但是,不幸的是,那不是问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值