web-dev-qa-db-ja.com

C関数の引数のデフォルト値とCの関数のオーバーロード

C++ libをANSI Cに変換すると、ANSI Cは関数変数のデフォルト値をサポートしていないように見えますが、それとも間違っていますか?私が欲しいのは

int funcName(int foo, bar* = NULL);

また、ANSI Cでは関数のオーバーロードは可能ですか?

必要になる

const char* foo_property(foo_t* /* this */, int /* property_number*/);

const char* foo_property(foo_t* /* this */, const char* /* key */, int /* iter */);

もちろん、単にそれらに異なる名前を付けることはできますが、C++に慣れているので、オーバーロード機能を使用していました。

19
inquam

いいえ、標準Cもサポートしていません。 C++コードをCに変換する必要があると思うのはなぜですか? C++をCから呼び出せるようにする必要がある場合は、ラッパーを書くのが良い方法だと思っていました。

27
anon

それにもかかわらず、GCCを使用している場合は、そのための「トリック」を見つけました。

GCCには、可変引数マクロに便利な##拡張機能があり、デフォルトの引数をシミュレートできます。

トリックには制限があります。これは1つのデフォルト値に対してのみ機能し、引数は最後の関数パラメーターでなければなりません。

これが実際の例です。

#include <stdio.h>


#define SUM(a,...) sum( a, (5, ##__VA_ARGS__) )

int sum (a, b)
  int a;
  int b;
{
  return a + b;
}


main()
{

  printf("%d\n", SUM( 3, 7 ) );

  printf("%d\n", SUM( 3 ) );

}

この場合、SUMを、デフォルトの2番目の引数が5であるsumの呼び出しとして定義します。

2つの引数を指定して呼び出す場合(メインでの最初の呼び出し)、次のように処理されます。sum(3、(5、7));

これの意味は:

  • 1番目の引数は3です
  • 2番目の引数はシーケンス(5、7)の結果です...これは明らかに7です!

Gccは賢いので、シーケンスの最初のメンバーは定数であり、それは必要ないため、これはランタイムに影響を与えません。コンパイル時に単に破棄されます。

引数を1つだけ指定して呼び出す場合、gcc拡張機能はVA_ARGS [〜#〜] and [〜#〜]先頭のコマを削除します。したがって、次のように前処理されます。

sum(3、(5));

したがって、プログラムは期待される出力を提供します。

10
8

したがって、これは2つの引数を持つ関数を(通常のマクロの制限で)完全にシミュレートします。最後の引数はオプションであり、提供されない場合はデフォルト値が適用されます。

19
user941239

これを試して。

#include <stdio.h>
#include <stdarg.h>

/* print all non-negative args one at a time;
   all args are assumed to be of int type */
void printargs(int arg1, ...)
{
  va_list ap;
  int i;

  va_start(ap, arg1); 
  for (i = arg1; i >= 0; i = va_arg(ap, int))
    printf("%d ", i);
  va_end(ap);
  putchar('\n');
}

int main(void)
{
   printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
   printargs(84, 51, -1);
   printargs(-1);
   printargs(1, -1);
   return

 0;
}
4
user7828

私の知る限り、ANSI Cは関数のオーバーロードまたはデフォルトの引数を直接サポートしていません。オーバーロードの標準的な代用は、引数の型を示す関数名に接尾辞を追加することです。たとえば、OpenGLでは、関数名の「3fv」接尾辞は、関数が3つの浮動小数点のベクトルを取ることを意味します。

デフォルト引数は、関数のオーバーロードの特殊なケースと見なすことができます。

3
Amnon

必要なだけのデフォルトパラメータをサポートする方法があります。構造体を使用するだけです。

// Populate structure with var list and set any default values
struct FooVars {
  int int_Var1 = 1;  // One is the default value
  char char_Command[2] = {"+"};
  float float_Var2 = 10.5;
};
struct FooVars MainStruct;

//...
// Switch out any values needed, leave the rest alone
MainStruct.float_Var2 = 22.8;
Myfunc(MainStruct);  // Call the function which at this point will add 1 to 22.8.
//...

void Myfunc( struct FooVars *MyFoo ) {
  switch(MyFoo.char_Command) {
    case '+':
      printf("Result is %i %c %f.1 = %f\n" MyFoo.int_Var1, MyFoo.char_Command, MyFoo.float_Var2, (MyFoo.float_Var2 + MyFoo.int_Var1);
      break;
    case '*':
      // Insert multiply here, you get the point...
      break;
    case '//':
      // Insert divide here...
      break;
  }
}
3
John Ritchie

ANSI Cにはデフォルト値も関数のオーバーロードも存在しないため、別の方法で解決する必要があります。

1
Hans Insulander

Cはそれらをサポートしていないので、それほど簡単にはできません。 「偽のオーバーロード」を取得する最も簡単な方法は、すでに述べたようにサフィックスを使用することです。デフォルト値は、可変引数関数を使用してシミュレートでき、渡された引数の数を指定し、プログラムでデフォルトを欠落しているものに与えます。例:

 aType aFunction(int nargs, ...)
 {
   // "initialization" code and vars
   switch(nargs)
   {
     case 0:
         // all to default values... e.g.
         aVar1 = 5; // ...
         break;
     case 1:
         aVar1 = va_arg(arglist, int); //...
         // initialize aVar2, 3, ... to defaults...
         break;
     // ...
   }
 }

また、オーバーロードは、追加および渡される追加情報とエクストラコードを含むvar argsを使用してシミュレートできます...基本的に、ミニマリストのオブジェクト指向ランタイムを再現します...別の解決策(または実際には同じですが、異なるアプローチ)は、タグを使用できます:各引数ペア引数タイプ+引数(可能な引数タイプのセット全体の和集合)、特別なターミネータータグ(渡される引数の数を指定する必要はありません)、そしてもちろん、常に "コラボレーション"が必要ですつまり、タグを解析し、実行する実際の関数を選択するための追加のコードが含まれている必要があります(これは一種のディスパッチャのように動作します)。

1
ShinTakezou

Cは name mangling を行わないため、Cでオーバーロードされた各関数を異なる方法で宣言する必要があります。あなたのケースでは "foo_property1" "foo_property2"。

0
INS