デフォルトパラメータ



変分関数
現代の言語(PythonやJavaScriptのような)は良い機能を持っています:関数は変数の数の引数を持つことができます.また、指定されていない引数のデフォルト値を定義することもできます.
これはプログラミングのより簡潔なスタイルを許容します.
Cは、変数の数(可変関数と呼ばれる)を持つ関数をstdarg.h ヘッダva_start() , va_copy() , va_arg() and va_end() これにより、引数のリストをスキャンできます.
彼らは何もないし、何もない、私は彼らが本当に使用し、いくつかの欠点を持っているとしてそれを好きにしたことがない:
  • パラメータの終わりを示す方法を定義する必要があります.例えば、printf() フォーマットする文字列をスキャンし、期待するパラメータ数を知るexecl() 渡す必要がありますNULL を返します.
  • パラメータの型チェックはありません.これは時々有用であるが、一般的ではなく、バグを見つけるのを難しくする.
  • 既定値は、関数自体の論理で定義されなければなりません.
  • また、変数マクロの引数を持つマクロ変数マクロを提供します.それらを使用することを避けるためにいくつかの方法がありますstdarg.h そして、我々の日を保存してください.私がここで例で使用する最もきれいなものをここに提示します、そして、以下で、これがどのように達成されるかについて示します.
    例:定義しましょうgreet() つの引数(名前とメッセージ)を受け取り、あいさつメッセージを出力する関数ですが、2番目の引数を省略することができます.指定されない場合は、デフォルトのメッセージが使用されます.
    #include <stdio.h>
    #include "vrg.h"
    
    char * msg_default = "How are you?";
    #define greet(...)   vrg(greet, __VA_ARGS__)
    #define greet1(n)    greetX(n, msg_default)
    #define greet2(n, m) greetX(n, m)
    
    void greetX(char *name, char *msg) {
      printf("Hello %s. %s\n", name, msg);
    }
    
    int main(int argc, char *argv[]) {
      greet("Alice", "How's your day?");
      greet("Bob"); // too lazy to think of a greeting for Bob
    }
    
    上のコードは出力を生成します.
    Hello Alice. How's your day?
    Hello Bob. How are you?
    
    私たちがしたことは
  • 名前の関数が多少異なります(greetX() ) そして、我々が普通にするようにそれを書きます.
  • 定義するgreet() Variadicマクロとして(関数ではなく)
  • 定義するgreet1() マクロの場合、greet ()マクロは1つの引数だけで呼び出されます.
  • 定義するgreet2() マクロの場合、greet ()マクロは2つの引数で呼び出されます.
  • それはかなりよく動作し、それは私よりはるかに書くことstdarg.h . この特定のケースがカバーするのが不可能であると言及しない限りstdarg.h の動作以来va_arg() 引数が存在しない場合は未定義です!
    あなたが少なくとも1つの引数を持たなければならないという制限があります、しかし、あなたが使うとき、これは真実ですstdarg.h . GCCは0の引数を扱うことができる拡張子を持っていますが、C 99に滞在したいです.

    フードの下で
    トリックはvrg.h 上記のコードに含まれるファイルvrg のためのニーモニックとして役立つvariadic arguments .
    私はまだGithubにそれを置いていないのでvrg.h こちら
    #define vrg_cnt(vrg1,vrg2,vrg3,vrg4,vrg5,vrg6,vrg7,vrg8,vrgN, ...) vrgN
    #define vrg_argn(...)  vrg_cnt(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    #define vrg_cat0(x,y)  x ## y
    #define vrg_cat(x,y)   vrg_cat0(x,y)
    
    #define vrg(vrg_f,...) vrg_cat(vrg_f, vrg_argn(__VA_ARGS__))(__VA_ARGS__)
    
    最初の2つのマクロは引数の数を数えます.これは8つ以上の引数に制限されています.なぜなら、いくつかの引数(そして8つの引数がたくさんある)で関数を書いていたなら、私はその関数をどのように構成したかに大きな問題がありました.単純にあまりにも多くの引数を持つ関数を言う!
    他の2つのマクロは、区分的に識別子を作成する標準的な方法です.
    最後のものはすべてをまとめ、引数の数によって異なる関数(またはマクロ)を呼び出します.
    このマクロは各引数が一度だけ評価されるので安全です.