GetProcAddressで呼ぶ関数にデフォルト引数はセットされない

関数に修正を加えたい場合に、なるべくプログラムに変更を加えないようにするためにデフォルト引数を加える場合があります。そうすれば今すでに動いているプログラムはデフォルト引数を受け取って動くことになるからです。
しかし、場合によっては影響を与えてしまいます。
例えばHoge.dllで int GetNumber(void) という関数を定義したとします。*1

int GetNumber(void) {
  return 1;
}

別の実行ファイルでLoadLibraryとGetProcAddressを使ってHoge.dllのGetNumber関数を呼びます。

HMODULE hModule = ::LoadLibrary("Hoge.dll");
typedef int (*GetNumberFunc)();
GetNumberFunc fun = (GetNumberFunc)::GetProcAddress("GetNumber");
int number = fun(); // => 1

ここでは当然numberは1になります。


ここでGetNumberに引数を渡してその値を返すように変更します。そのときにGetNumberを呼んでいるところに影響を与えないためにデフォルト引数に1をセットしておきます。

int GetNumber(int number=1) {
  return number;
}

こうしておけばすでにGetNumberを呼び出しているところでは1を返しますし、引数を受け取った時はその値を返すようになります。
しかし、残念ながらGetProcAddressを利用してこの関数を呼ぶと期待した値が返って来ません。

HMODULE hModule = ::LoadLibrary("Hoge.dll");
typedef int (*GetNumberFunc)();
GetNumberFunc fun = (GetNumberFunc)::GetProcAddress("GetNumber");
int number = fun(); // => 0(不定)

これはおそらくデフォルト引数はコンパイラがあらかじめ処理してくれているので、プロトタイプ宣言のないデフォルト引数はコンパイラが解釈しようがないからだと思われます。
これを正しく動かすには、通常通りに型と値を与えてやる必要があります。

HMODULE hModule = ::LoadLibrary("Hoge.dll");
typedef int (*GetNumberFunc)(int);
GetNumberFunc fun = (GetNumberFunc)::GetProcAddress("GetNumber");
int number = fun(1); // => 1

*1:実際にはエクスポートやCの関数であることの宣言が必要です