- 『__cplusplus』の意味
- C言語とC++の呼び出し規約のサンプルプログラム
C/C++のコンパイラでは『 __cplusplus 』というプリプロセッサマクロが事前定義されます。実際の製品コードの中でもたまに見かけることがあります。本投稿では、この『 __cplusplus』マクロについて解説します。
実行環境は下表の通りです。
開発環境 | Microsoft Visual Studio Community 2019 Version 16.11.7 |
OS | Windows 10 バージョン21H1 |
使い方と意味
『 __cplusplus 』 は、C/C++のソースコード上で記述します。ifdef、ifndefと合わせて使用します。よく見かける使い方は下記です。
#ifdef __cplusplus C++独自仕様のコード #else C言語独自仕様のコード #endif
具体例としては、DLLで関数をエクスポートする際、名前マングリング有りと無しの関数を用意したい場合などに用いられます。
サンプルコード
サンプルで説明します。まずは、DLL側のコードです。エクスポートする関数は”SayHello”と”SayHello1″の2つですが、2関数には以下の違いがあります。
- SayHello …名前マングリング有り
- SayHello1 …名前マングリング無し
下記コードは、C++ソースファイルのため、コンパイル時に『 __cplusplus 』マクロが事前定義されます。
#include <stdio.h>
__declspec (dllexport) void SayHello(void)
{
printf("[SayHello]Hello!\n");
}
#ifdef __cplusplus // C++としてのコンパイルか
extern "C" __declspec (dllexport) void SayHello1(void)
{
printf("[SayHello1]__cplusplus defined.\n");
printf("[SayHello1]Hello!\n");
}
#endif
dumpbinによりエクスポート状況を確認すると、2関数がエクスポートされています。”SayHello”は『 __cplusplus 』を使用していないため、C++としてビルドされ、名前マングリングされています。他方、”SayHello1″は『 __cplusplus 』が有効のため、内部の”SayHello1″関数定義が実行されています。extern “C”が付加されているので、C言語の呼び出し規約による定義となり、名前マングリング無しになります。
テストメインプログラムからの関数呼び出し
作成したDLL(TestDll.dll)をテスト用のメインプログラムから呼び出します。
#include <stdio.h>
#include <Windows.h>
void main(void)
{
HMODULE hm = NULL;
FARPROC proc1 = NULL;
FARPROC proc2 = NULL;
hm = LoadLibrary(L"TestDll.dll");
if (hm == NULL)
{
printf("abnormal exit-1.\n");
return;
}
proc1 = GetProcAddress(hm, "?SayHello@@YAXXZ"); // 名前マングリング有りの関数
proc2 = GetProcAddress(hm, "SayHello1"); // 名前マングリング無しの関数
if (proc1 == NULL || proc2 == NULL)
{
printf("abnormal exit-2.\n");
return;
}
proc1();
proc2();
FreeLibrary(hm);
return;
}
実行結果は、以下の通りです。proc1()の呼び出しで、”SayHello”が実行されて、proc2()の呼び出しでは、”SayHello1″が実行されています。
まとめ
『 __cplusplus 』マクロを使い、名前マングリング有り無しの関数をエクスポートするDLLサンプルを作成しました。C言語とC++を混在して使う場面は、実際の現場ではよくあります。基本的にはC++で作成したプログラムでも、C言語でインターフェースしたい場合には、この仕掛けを理解し、活用してください。
コメント