【问题标题】:Help me understand this short chunk of code帮助我理解这段简短的代码
【发布时间】:2009-09-06 13:35:39
【问题描述】:

我知道这段代码计算了一个变量的 args 的总和,但是,我不明白它是如何工作的。它对我来说看起来很抽象。有人可以解释一下下面的工作原理吗?

谢谢!

#include <stdio.h>

#define sum(...) \
    _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ })

int _sum(size_t count, int values[])
{
    int s = 0;
    while(count--) s += values[count];
    return s;
}

int main(void)
{
    printf("%i", sum(1, 2, 3));
}

【问题讨论】:

  • 到目前为止的答案还不是很清楚,有人会好心评论代码并分解详细说明吗?谢谢!
  • @nubela,对不起,如果我的解释不够清楚。我已将 cmets 添加到您的代码中,希望可以使其更清晰。
  • @pax 哇,谢谢!欣赏它!尝试学习 C :)

标签: c


【解决方案1】:

使用预处理宏

#define sum(...) \
    _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ })

使用sum(1,2,3) 调用时,该行被翻译(一个简单的字符串替换,将"__VA_ARGS__" 替换为"1,2,3")为:

_sum(sizeof((int []){1,2,3}) / sizeof(int), (int []){1,2,3})

这是对_sum() 的函数调用,传递了两件事:

  • 数组 {1,2,3} 中的整数个数为 3(它通过将三整数数组的大小除以单个整数的大小得到)。
  • 指向数组本身的指针(或包含相同值的完全不同的数组,具体取决于您的编译器的智能程度)。

_sum() 函数所做的只是将每个整数添加到s(最初为零),直到计数用完。


上面的第一个要点有一些解释。当您有一个由N 元素组成的数组时,定义如下:

tType x[22];

数组的大小是sizeof(x),即所有元素的大小。该数组的单个元素的大小是sizeof(x[0]),即第一个元素的大小,尽管我通常更喜欢sizeof(*x) 变体。

因此,要计算元素的数量,您只需将总大小除以元素的大小,使用以下方法之一:

sizeof(x) / sizeof(x[0])
sizeof(x) / sizeof(*x)

而且,既然您要求对代码进行详细分析,那么我们开始吧:

// Needed for printf().

#include <stdio.h>

// Macro to convert sum(n1,n2,...,nN) to _sum(N,n1,n2,...,nN).
// This calculates the length of the array by dividing its size by the size
//   of an int and passes both the length and array through to the new
//   function.
// __VA_ARGS__ is replaced with the entire marcro argument list, '1,2,3' in
//   this case.

#define sum(...) \
    _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ })

// Function to take size and pointer to int array, and return sum.

int _sum (size_t count, int values[]) {
    int s = 0;                // Initial sum of zero.
    while(count--)            // Until elements exhausted (count down).
        s += values[count];   // Add each array element to accumulator.
    return s;                 // Return sum.
}

int main (void) {
    printf ("%i", sum(1, 2, 3));   // Test it with 1, 2 and 3 (should print 6).
}

【讨论】:

  • 这是我见过的关于可变长度参数列表的最佳描述
  • 是的。你应该写教科书!
【解决方案2】:

我们看一下宏的示例调用sum(1, 2, 3)的扩展

#define sum(...) \
    _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ })

... 表示它是一个可变参数宏,即它接受任意数量的逗号分隔参数。展开时,特殊的预处理器标记__VA_ARGS__ 将被这些参数替换,即

(int []){ __VA_ARGS__ }

扩展到

(int []){ 1, 2, 3 }

这是一个复合字面量:C99 允许通过这种类型化的初始化列表即时创建具有自动存储持续时间的对象。

重要的是要推断数组的大小:它不会有不完整的类型int [],而是类型int [3],即

sizeof((int []){ 1, 2, 3 }) = sizeof(int [3]) = 3 * sizeof(int)

要获取元素的数量,请除以sizeof(int)

宏调用sum(1, 2, 3)因此等价于C90代码

int tmp[3] = { 1, 2, 3 };
_sum(3, tmp);

【讨论】:

    【解决方案3】:

    在此代码中,sum 宏将 main 中的 sum(1,2,3) 调用转换为对 _sum 的调用,方法是使用 sizeof 计算调用 sum 的元素数量。包含三个值的int 数组的大小将是3 * sizeof(int),因此除以sizeof(int) 再次得到三个。

    【讨论】:

      【解决方案4】:

      给定一个整数数组,它会将其所有元素求和并返回该值。

      【讨论】:

        【解决方案5】:

        这里的预处理器使用可变数量的参数variadic macro。 休息它只是从参数列表中创建一个数组并对其进行操作

        【讨论】:

          猜你喜欢
          • 2011-02-21
          • 2010-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多