C宏与varargs

时间:2015-03-14 14:53:32

标签: c

我正在尝试编写一个宏,它返回几个整数的最小值。当我编译以下代码时,它会抛出错误“expected expression”。我不知道那里有什么问题。有人能指出这段代码的问题吗?

#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;
}

我只是对如何使用Macro感到好奇。

5 个答案:

答案 0 :(得分:7)

  

我很好奇如何使用Macro。

你不能。 va_list可变参数函数访问其参数的一种方法。你写的是可变参数宏。它们不一样(特别是可变参数宏仍然只是一种语法上的便利,不允许你处理单个参数)。做你想做的事的唯一方法是在可变参数宏中调用你自己设计的可变参数函数(然后你也可以消除宏)。

但是,如果你真的坚持使用一个可变参数宏,那么你很幸运在宏参数和数组初始值设定项中使用了相同的分隔符,,所以你可以尝试这样的:

#define F(X, ...) \
  do { \
    int t[] = { __VA_ARGS__ }; \
    for (int i = 0; i < sizeof t / sizeof t[0]; i++) \
      … \
  } while (0)

答案 1 :(得分:3)

我认为你不能。从gcc手册(https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html)中,您可以用标准方式做的最好的事情就是编写__VA_ARGS__,它将扩展参数(例如传递给函数)。

然后继续定义您可以使用的其他非标准扩展,但不会是标准扩展。

为什么不用功能呢?

答案 2 :(得分:1)

处理可变参数宏中的参数列表的方式与在可变参数函数中处理它们的方式不同。您可以使用va_list

,而不是使用__VA_ARGS__及其相关的宏

这几乎就是它的范围:你不能编写一个从头到尾处理可变列表的宏;您只能将参数传递给可变函数,该函数执行实际处理。

注意:您的实施也是错误的:您应该使用va_start(vl,ret_val)而不是va_start(vl,nums),因为您应该在{{1}之前传递最后一个参数} ...

但是,如果我将其重写为函数,我会删除va_start指针,并创建一个以常规方式返回值的函数。

答案 3 :(得分:0)

用宏来做这件事是没有意义的。这就是功能的用途。

您收到错误,因为主函数中的SMALLEST符号被您定义的函数的整个主体替换。 AFAIK您无法在C中的另一个函数内定义函数。

答案 4 :(得分: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偏移。

编辑:而且,正如其他人所说,你不能像你尝试的那样使用可变参数宏。