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++に慣れているので、オーバーロード機能を使用していました。
いいえ、標準Cもサポートしていません。 C++コードをCに変換する必要があると思うのはなぜですか? C++をCから呼び出せるようにする必要がある場合は、ラッパーを書くのが良い方法だと思っていました。
それにもかかわらず、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));
これの意味は:
Gccは賢いので、シーケンスの最初のメンバーは定数であり、それは必要ないため、これはランタイムに影響を与えません。コンパイル時に単に破棄されます。
引数を1つだけ指定して呼び出す場合、gcc拡張機能はVA_ARGS [〜#〜] and [〜#〜]先頭のコマを削除します。したがって、次のように前処理されます。
sum(3、(5));
したがって、プログラムは期待される出力を提供します。
10
8
したがって、これは2つの引数を持つ関数を(通常のマクロの制限で)完全にシミュレートします。最後の引数はオプションであり、提供されない場合はデフォルト値が適用されます。
これを試して。
#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;
}
私の知る限り、ANSI Cは関数のオーバーロードまたはデフォルトの引数を直接サポートしていません。オーバーロードの標準的な代用は、引数の型を示す関数名に接尾辞を追加することです。たとえば、OpenGLでは、関数名の「3fv」接尾辞は、関数が3つの浮動小数点のベクトルを取ることを意味します。
デフォルト引数は、関数のオーバーロードの特殊なケースと見なすことができます。
必要なだけのデフォルトパラメータをサポートする方法があります。構造体を使用するだけです。
// 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;
}
}
ANSI Cにはデフォルト値も関数のオーバーロードも存在しないため、別の方法で解決する必要があります。
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を使用してシミュレートできます...基本的に、ミニマリストのオブジェクト指向ランタイムを再現します...別の解決策(または実際には同じですが、異なるアプローチ)は、タグを使用できます:各引数ペア引数タイプ+引数(可能な引数タイプのセット全体の和集合)、特別なターミネータータグ(渡される引数の数を指定する必要はありません)、そしてもちろん、常に "コラボレーション"が必要ですつまり、タグを解析し、実行する実際の関数を選択するための追加のコードが含まれている必要があります(これは一種のディスパッチャのように動作します)。
Cは name mangling を行わないため、Cでオーバーロードされた各関数を異なる方法で宣言する必要があります。あなたのケースでは "foo_property1" "foo_property2"。