C宏与变参

4

我正在尝试编写一个宏,它返回多个整数中的最小值。当我编译以下代码时,它会抛出一个“预期表达式”的错误。我不知道哪里错了。有谁能指出这段代码的问题吗?

#define SMALLEST (nums, (ret_val), ...)          \
do {                                             \
    int i, val;                                  \
    va_list vl;                                  \
    va_start(vl,nums);                           \
    (*ret_val) = va_arg(vl, int);                \
    for (i = 1; i < nums; i++)                   \
    {                                            \
        val=va_arg(vl, int);                     \
        if ((*ret_val) > val)                    \
            (*ret_val) = val;                    \
    }                                            \
    va_end(vl);                                  \
} while(0)

int main ()
{
  int nums = 3;
  int ret_val = 0;
  SMALLEST(nums, &ret_val, 1, 2, 3);
  return 0;
}

我对如何使用宏进行操作很感兴趣。

你的宏语法有误。宏名称和 () 之间不应该有空格。在参数列表中,宏参数不能放在额外的 () 中。 - Jens Gustedt
5个回答

11
我只是好奇如何使用宏来实现。但是,你不能这样做。va_list是一种让可变参数函数访问其参数的方法。而你所编写的是可变参数宏。它们不同(特别是可变参数宏仍然只是一个语法上的便利,无法让你处理单个参数)。唯一的方法是在可变参数宏中调用自己设计的可变参数函数(然后你可能会直接删除宏)。但是,如果你真的坚持使用可变参数宏,那么你很幸运,因为宏参数和数组初始化器都使用相同的分隔符“,”,所以你可以尝试类似于以下内容:
#define F(X, ...) \
  do { \
    int t[] = { __VA_ARGS__ }; \
    for (int i = 0; i < sizeof t / sizeof t[0]; i++) \
      … \
  } while (0)

3
我认为你做不到。从gcc手册(https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html)中可以看到,你最好的选择是以标准方式编写__VA_ARGS__,它会在原地展开参数(例如传递给函数)。
然后手册定义了其他非标准扩展,你可能能够使用,但这些扩展并不是标准的。
为什么不用函数来实现呢?

1
在可变宏中处理参数列表的方式与在可变函数中处理它们的方式不同。您使用__VA_ARGS__而不是使用va_list及其相关宏。
这基本上就是全部内容:您无法编写从开头到结尾处理可变列表的宏;您仅限于将参数传递给可变函数,由可变函数执行实际处理。
注意:您的实现也是不正确的:应该使用va_start(vl,ret_val)而不是va_start(vl,nums),因为您应该将...之前的最后一个参数传递给va_start
但如果我要将其重写为函数,我会放弃ret_val指针,并制作一个按常规方式返回值的函数。

0

你想在这里使用宏的特定原因是什么?你似乎混淆了宏语法和标准语法(这是你出错的原因)。

你应该使用函数来实现这个目的 - 这就是函数的作用。以下代码应该可以帮助你得到想要的结果:

int Smallest( int iNumberOfIntegers, ... )
{
    va_list args = NULL;
    int i = 0;
    int iSmallestValue = 0;
    int iCurrentValue = 0;

    va_start( args, iNumberOfIntegers );
    iSmallestValue = va_arg( args, int );

    for(i = 0; i < iNumberOfIntegers - 1; i++)
    {
        iCurrentValue = va_arg( args, int );
        if(iSmallestValue > iCurrentValue)
        {
            iSmallestValue = iCurrentValue;
        }
    }

    return iSmallestValue;
}

需要注意的是,如果您要以这种方式循环遍历可变参数,则需要传递其大小。在格式字符串中不需要这样做,因为编译器可以从格式字符串说明符中推断出数量。 我们从循环中减去1来解决0偏移量的问题。 编辑:正如其他人所说,您不能像尝试的那样使用可变宏。

0

使用宏来做这件事毫无意义,因为这就是函数的作用。

您会收到错误,因为在主函数中,SMALLEST符号被定义的整个函数体替换。据我所知,在C语言中不能在一个函数内定义另一个函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接