Cで可変長引数のみを取る関数を作る


Cで可変長引数のみを取る関数を作りたいのですが、どのようにすればいいのでしょうか?  
下の例のように、最初に可変長引数の数を示すcounterのような引数を取り、その数を元にforで値を得るものはよく見かけますが、これを
average(10, 20, 30) というふうに可変長引数のみを取り、結果を返すにはどうすればいいのでしょうか?

Macを使っているため、コンパイラはclangです。

[code]

    #include <stdarg.h>
    
    double average(int count, ...) {
        va_list ap;
        int j;
        double sum = 0;
    
        va_start(ap, count);
        for (j = 0; j < count; j++) {
            sum += va_arg(ap, double);
        }
    
        va_end(ap);
        return sum / count;
    }
    
    #average(10, 20, 30) -> 20と返ってくるようにしたい
    
[/code]

コードの引用元:
[Wikipedia:可変長引数](http://ja.wikipedia.org/wiki/%E5%8F%AF%E5%A4%89%E9%95%B7%E5%BC%95%E6%95%B0)




C99の[可変個引数マクロ](http://seclan.dll.jp/c99d/c99d02.htm#dt19990405)と[複合リテラル](http://seclan.dll.jp/c99d/c99d07.htm#dt19991101)を使えば強引に実現可能です。（おすすめできませんが）

[code]

    #include <stdarg.h>
    
    double average_impl(int count, ...) {
        va_list ap;
        va_start(ap, count);
        double sum = 0.0;
        for (int i = 0; i < count; i++) {
            double v = va_arg(ap, double);
            sum += v;
        }
        va_end(ap);
        return sum / count;
    }
    
    #define count_vsargs(...)  (sizeof((double[]){__VA_ARGS__}) / sizeof(double))
    #define average(...)  average_impl(count_vsargs(__VA_ARGS__), __VA_ARGS__)
    
[/code]

呼び出し側コード：

[code]

    average(10.0, 20.0, 30.0);
    // average_impl(3, 10.0, 20.0, 30.0)に展開される
    
[/code]

LiveDemo: <http://melpon.org/wandbox/permlink/zAxIsh9m7AWvMu9q>

* * *

追記：個人的におすすめできない理由としては、1)呼び出し時に整数リテラルを渡すと正常動作しない、2)マクロによる技巧に走った実装である、3)そもそもC99標準の機能自体がマイナーなため保守性に疑問符あたりです。

特に1)は深刻で、呼び出し側コードを`average(10.0, 20.0, 30.0);`から`average(10, 20,
30);`に変えると、前掲コードは正常動作する保証が無くなります（偶然に動く場合もあります）。これはC言語の可変長引数による大きな落とし穴の一つです。良くある不具合パターンは、下記`printf`関数の例でしょう。

[code]

    // NG: 期待通り動作しない！
    printf("%f\n", 10);
    // 書式指定"%f"でdouble型を要求するが、`10`はint型リテラルのため型不一致
    
    // OK: 期待通り動作する
    printf("%f\n", 10.0);
    
[/code]

@HiroshiYamamotoさん[実装](https://ja.stackoverflow.com/a/4415/49)では、コンパイラによる型変換が行われるため、前掲実装コードより少しだけ安全側に倒れます。（元質問に合わせs/`int`/`double`/gとしてコード引用します）

[code]

    #define average(...) ( \
      _average((double[]){__VA_ARGS__}, sizeof((double[]){__VA_ARGS__}) / sizeof(double)) )
    
    double _average(int double[], size_t size)
    {
      if (!size) return 0.0;
      double sum = 0.0;
      size_t i = 0;
      while (i < size) sum += nums[i++];
      return sum / size;
    }
    
[/code]

呼び出し側コード`average(10, 20, 30)`は、`_average((double[]){10, 20, 30},
～)`とマクロ展開され、1個目の引数では`(double[]){...}`＝「double型配列の複合リテラル」が明記されます。このため、可変長引数では起こり得た呼出元の型と`va_args`取得時の型不一致が起こりません。




C99の[可変個引数マクロ](http://seclan.dll.jp/c99d/c99d02.htm#dt19990405)と[複合リテラル](http://seclan.dll.jp/c99d/c99d07.htm#dt19991101)を使えば強引に実現可能です。（おすすめできませんが）

[code]

    #include <stdarg.h>
    
    double average_impl(int count, ...) {
        va_list ap;
        va_start(ap, count);
        double sum = 0.0;
        for (int i = 0; i < count; i++) {
            double v = va_arg(ap, double);
            sum += v;
        }
        va_end(ap);
        return sum / count;
    }
    
    #define count_vsargs(...)  (sizeof((double[]){__VA_ARGS__}) / sizeof(double))
    #define average(...)  average_impl(count_vsargs(__VA_ARGS__), __VA_ARGS__)
    
[/code]

呼び出し側コード：

[code]

    average(10.0, 20.0, 30.0);
    // average_impl(3, 10.0, 20.0, 30.0)に展開される
    
[/code]

LiveDemo: <http://melpon.org/wandbox/permlink/zAxIsh9m7AWvMu9q>

* * *

追記：個人的におすすめできない理由としては、1)呼び出し時に整数リテラルを渡すと正常動作しない、2)マクロによる技巧に走った実装である、3)そもそもC99標準の機能自体がマイナーなため保守性に疑問符あたりです。

特に1)は深刻で、呼び出し側コードを`average(10.0, 20.0, 30.0);`から`average(10, 20,
30);`に変えると、前掲コードは正常動作する保証が無くなります（偶然に動く場合もあります）。これはC言語の可変長引数による大きな落とし穴の一つです。良くある不具合パターンは、下記`printf`関数の例でしょう。

[code]

    // NG: 期待通り動作しない！
    printf("%f\n", 10);
    // 書式指定"%f"でdouble型を要求するが、`10`はint型リテラルのため型不一致
    
    // OK: 期待通り動作する
    printf("%f\n", 10.0);
    
[/code]

@HiroshiYamamotoさん[実装](https://ja.stackoverflow.com/a/4415/49)では、コンパイラによる型変換が行われるため、前掲実装コードより少しだけ安全側に倒れます。（元質問に合わせs/`int`/`double`/gとしてコード引用します）

[code]

    #define average(...) ( \
      _average((double[]){__VA_ARGS__}, sizeof((double[]){__VA_ARGS__}) / sizeof(double)) )
    
    double _average(int double[], size_t size)
    {
      if (!size) return 0.0;
      double sum = 0.0;
      size_t i = 0;
      while (i < size) sum += nums[i++];
      return sum / size;
    }
    
[/code]

呼び出し側コード`average(10, 20, 30)`は、`_average((double[]){10, 20, 30},
～)`とマクロ展開され、1個目の引数では`(double[]){...}`＝「double型配列の複合リテラル」が明記されます。このため、可変長引数では起こり得た呼出元の型と`va_args`取得時の型不一致が起こりません。

