Visual C++
アセンブラの魔女 ⧫ Windows ⧫ Visual Studio ⧫ Visual C++
アセンブラの魔女 ⧫ Windows ⧫ Visual Studio ⧫ Visual C++
宣言
 識別子
  inline, __inline, __forceinline(関数のインライン展開)
Microsoft依存のモディファイア
 __cdecl
 __declspec
 __stdcall
ヘッダ注釈
 バッファ注釈
 アドバンスド注釈
ライブラリ
 ランタイムライブラリ
  Cランタイムライブラリ

 inline識別子と__inline識別子はコンパイラに関数が呼ばれるそれぞれの場所に関数のコピーを挿入する(関数のインライン展開)ように指示します。

inline function_declarator;   
__inline function_declarator;        // Microsoft Specific
__forceinline function_declarator;   // Microsoft Specific

 挿入(インライン展開)はコンパイラの評価の結果有利だと判断された場合に限り発生します。インライン展開は関数コールにともなうオーバヘッドを軽減すると同時にコードサイズを大きくします。forceinlineキーワードはコンパイラではなくプログラマにインライン展開が有利かどうかの判断を委ねます(このキーワードを使うと強制的にインライン展開する)。安易に__forceinlineを使うとコードが大きくなるばかりで、些細な効率しかもたらさないか、場合によっては依然効率は改善しないかもしれません(実行ファイルの巨大化によって)。インライン関数を使うと関数コールにともなうオーバヘッドが取り除かれるのでプログラムの実行速度を改善することができます。

__based
__cdecl(C/C++のデフォルトの呼び出し規約のための修飾子)
__declspec(記憶クラスの詳細な属性を指定)
__fastcall
__restrict
__stdcall(__stdcall呼び出し規約のための修飾子)
__w64
__unaligned

 これはCとC++のデフォルトの呼び出し規約です。スタックは呼び出し側でクリーンアップされるので、可変長引数を持つ関数をそのまま呼び出すことができます。__stdcallは呼ばれる側がスタックをクリーンアップしますので、可変長引数を持つ関数には使えません。以下にこの呼び出し規約の内容を示します。

引数の渡される順番右から左
スタック操作引数の渡される順番呼び出し側が(関数コール後)引数に使ったスタックをポップする
名前修飾規約Cのリンクを用いる__cdecl関数を除いて、名前の先頭にプリフィクス文字'_'が付加される
Case翻訳規約case翻訳されない

 Itaniumプロセッサファミリ(IPF)とx64プロセッサでは、__cdeclはコンパイラによって受け入れられますが無視されます(これはIPFの場合、呼び出し規約で引数がレジスタ渡しされるためです)。  cdecl修飾子は変数または関数名の前に置きます。Cの名前規約と呼び出し規約がデフォルトなので/Gz(stdcall)または/Gr(fastcall)コンパイラオプションを指定するときだけ、__cdecl を用います。/Gdコンパイラオプションを使うと強制的に__cdecl呼び出し規約が適用されます。

 ANSI仕様のC, C++では記憶クラスとして、staicやexternキーワードが用意されていますが、これ以外の記憶クラスを指定することができません。Visual Studioでは__declspecキーワードを使って、さらに詳細な記憶クラスの属性を指定することができます。たとえば、threadを指定するとスレッドローカルストレージを指定することができます。

__declspec ( extended-decl-modifier-seq )

 __stdcall呼び出し規約はWin32 API関数の呼び出しに用いられます。この規約を使う関数の呼び出しでは、呼び出し側はスタックをクリアし、コンパイラは可変長引数を持つ関数に_cdeclを使います。この呼び出し規約を使う関数は関数のプロトタイプを必要とします。

 ライブラリの仕様を調べると、特殊な表記(注釈, annotations)が見つかることがあります。たとえば、次のような表記です。

_In_z and _Out_z_cap_(_Size)

 これらの表記はSAL(Microsoft source-code annotation language)による記述です。SALは関数がパラメータを使う方法を説明する注釈(annotations )のセットを提供します。このような表記はヘッダ注釈(Header annotations)またはSAL注釈(SAL annotations)と呼ばれます。 msdnではヘッダ注釈とSAL注釈が別々に説明されているので混乱しますが、両者は同じことを意味しているようです。 以下では「ヘッダ注釈」という呼び方に統一します。

 ヘッダ注釈は関数の型の前、または関数値の前に置くことができ、パラメータや関数値に関する関数の振る舞いを説明するために用いられます。これらの注釈はAPIが正しくコールされるようにWindowsの多くのヘッダファイルで追加されています。コード解析(code analysis)の機能(Visual Studio 2005で追加された)を使うと、コンパイラはヘッダ注釈で指定された方法に従わない関数コールに対してレベル6000のワーニングを生成します。 ヘッダ注釈はユーザーのプログラムでも利用することができます。ヘッダ注釈はSpecstrings.h内で定義され、Standard Annotation Language (SAL)の一部で組み込みプリミティブとして以下を使って実装されます。

_declspec("SAL_*")

 注釈にはバッファ注釈(buffer annotations)とアドバンスド注釈(advanced annotations)の2つのクラスがあります。

 バッファ注釈は関数がポインタをどのように使うかを説明しバッファオーバーランを検出できるようにします。そ れぞれのパラメータはゼロまたは1つのバッファ注釈を使うことができます。 バッファ注釈は先頭のアンダースコアと以下で説明するコンポーネントによって構成されます。それぞれのパラメータには、1つのバッファ注釈のみ使用できます。

分類オプション説明
Indirection パラメータまたは戻り値pとバッファポインタとの間接レベルを示します。
none pがバッファポインタ。
_deref *pがバッファポインタ。pはNULL以外の値である必要があります。
_deref_opt *pはバッファポインタである可能性があります。pにはNULLを指定することができます。この場合、残りの注釈は無視されます。
Direction 関数が(入出力に関して)バッファをどのように使用するかを示します。
none パラメータに対してこのカテゴリの注釈が用いられない場合、このバッファはアクセスされません。
戻り値に対して用いられこのカテゴリの注釈が用いられない場合、または _derefが用いられてこのカテゴリの注釈が用いられない場合、関数がバッファを提供し、終了時に初期化前の状態に戻します。
上記以外の場合、呼び出し元がバッファを提供します(alloc 関数と free 関数に対してのみ使用可能)。
_in 関数はこのバッファに対して読み込みのみを行います。呼び出し側がバッファを提供し初期化する必要があります。この注釈を_deref と一緒に使用することはできません。
_inout 関数はこのバッファに対して読み込みと書き込みの両方を行うことができます。呼び出し側がバッファを提供し初期化する必要があります。_deref と一緒に使用する場合、バッファは関数によってリロケートされるかも知れません。
_out 関数はこのバッファへに対しての書き込みのみを行います。
戻り値に対してこの注釈を用いる場合、または _deref と共に用いる場合、関数がバッファを提供し、終了時に初期化前の状態に戻します。
上記以外の場合、呼び出し側がバッファを提供し、関数がこれを初期化します。
Buffer size units バッファの合計(アクセス可能な)サイズの単位を示します
none このバッファサイズは指定されません。型がバッファサイズを指定する場合 (LPSTR、LPWSTR など)、サイズは型によって指定されます。それ以外の型ではバッファのサイズは1要素分のサイズになります。_in, _out, _inoutのいずれかと一緒に用いる必要があります。
_bcount バッファ サイズは明示的なバイト数
_ecount バッファ サイズは明示的な要素数
Buffer size バッファのサイズを指定します。
none バッファのサイズは明示的に指定されません。この場合、_ecount も _bcount も使用されません。
(size) バッファの合計サイズのみを指定します。_ecountや_bcountと一緒に用いられ、_part とは一緒に用いられません。
(size,length) バッファの合計サイズsizeと初期済みのサイズ(length)を指定します。_ecount_partや _bcount_partと一緒に用いられます。
Initialization 関数によるバッファの初期化に関する振る舞いを指定します。
none 注釈ではなく型によって初期化レベルを指定します。たとえば、LPWSTR を初期化する関数は、文字列はNULLで終端される必要があります。
_full 関数は出力バッファ全体を初期化します。出力バッファでのみ用いられます。
_part 関数は出力バッファの一部を初期化し、初期化したサイズを明示します。出力バッファでのみ用いられます。
Null-termination バッファがNULLで終端されるかどうかを指定します。
_z バッファの終端はNULLによって示されます
_nz NULLはバッファの終端を表しません(バッファはNULLで終わらない場合があります)。
Optional このバッファが省略可能であるかどうかを示します。
none このバッファへのポインタはNULL以外の値である必要があります(省略不可)。
_opt このバッファへのポインタはNULLを指定することで省略することができます。

GetModuleFileName関数の仕様書でのバッファ注釈の例で、hModuleはオプショナルな入力パラメータ、lpFilenameは出力パラメータ、nSizeパラメータは入力パラメータとして定義されています。

 以下はSpecstrings.hで定義されている注釈(annotations )です。これらの意味を解析するには上記のテーブルの情報を参照してください。

__bcount(size)
__bcount_opt(size)
__deref_bcount(size)
__deref_bcount_opt(size)
__deref_ecount(size)
__deref_ecount_opt(size)
__deref_in
__deref_in_bcount(size)
__deref_in_bcount_opt(size)
__deref_in_ecount(size)
__deref_in_ecount_opt(size)
__deref_in_opt
__deref_inout
__deref_inout_bcount(size)
__deref_inout_bcount_full(size)
__deref_inout_bcount_full_opt(size)
__deref_inout_bcount_opt(size)
__deref_inout_bcount_part(size,length)
__deref_inout_bcount_part_opt(size,length)
__deref_inout_ecount(size)
__deref_inout_ecount_full(size)
__deref_inout_ecount_full_opt(size)
__deref_inout_ecount_opt(size)
__deref_inout_ecount_part(size,length)
__deref_inout_ecount_part_opt(size,length)
__deref_inout_opt
__deref_opt_bcount(size)
__deref_opt_bcount_opt(size)
__deref_opt_ecount(size)
__deref_opt_ecount_opt(size)
__deref_opt_in
__deref_opt_in_bcount(size)
__deref_opt_in_bcount_opt(size)
__deref_opt_in_ecount(size)
__deref_opt_in_ecount_opt(size)
__deref_opt_in_opt
__deref_opt_inout
__deref_opt_inout_bcount(size)
__deref_opt_inout_bcount_full(size)
__deref_opt_inout_bcount_full_opt(size)
__deref_opt_inout_bcount_opt(size)
__deref_opt_inout_bcount_part(size,length)
__deref_opt_inout_bcount_part_opt(size,length)
__deref_opt_inout_ecount(size)
__deref_opt_inout_ecount_full(size)
__deref_opt_inout_ecount_full_opt(size)
__deref_opt_inout_ecount_opt(size)
__deref_opt_inout_ecount_part(size,length)
__deref_opt_inout_ecount_part_opt(size,length)
__deref_opt_inout_opt
__deref_opt_out
__deref_opt_out_bcount(size)
__deref_opt_out_bcount_full(size)
__deref_opt_out_bcount_full_opt(size)
__deref_opt_out_bcount_opt(size)
__deref_opt_out_bcount_part(size,length)
__deref_opt_out_bcount_part_opt(size,length)
__deref_opt_out_ecount(size)
__deref_opt_out_ecount_full(size)
__deref_opt_out_ecount_full_opt(size)
__deref_opt_out_ecount_opt(size)
__deref_opt_out_ecount_part(size,length)
__deref_opt_out_ecount_part_opt(size,length)
__deref_opt_out_opt
__deref_out
__deref_out_bcount(size)
__deref_out_bcount_full(size)
__deref_out_bcount_full_opt(size)
__deref_out_bcount_opt(size)
__deref_out_bcount_part(size,length)
__deref_out_bcount_part_opt(size,length)
__deref_out_ecount(size)
__deref_out_ecount_full(size)
__deref_out_ecount_full_opt(size)
__deref_out_ecount_opt(size)
__deref_out_ecount_part(size,length)
__deref_out_ecount_part_opt(size,length)
__deref_out_opt
__ecount(size)
__ecount_opt(size)
__in
__in_bcount(size)
__in_bcount_opt(size)
__in_ecount(size)
__in_ecount_opt(size)
__in_opt
__inout
__inout_bcount(size)
__inout_bcount_full(size)
__inout_bcount_full_opt(size)
__inout_bcount_opt(size)
__inout_bcount_part(size,length)
__inout_bcount_part_opt(size,length)
__inout_ecount(size)
__inout_ecount_full(size)
__inout_ecount_full_opt(size)
__inout_ecount_opt(size)
__inout_ecount_part(size,length)
__inout_ecount_part_opt(size,length)
__inout_opt
__out
__out_bcount(size)
__out_bcount_full(size)
__out_bcount_full_opt(size)
__out_bcount_opt(size)
__out_bcount_part(size,length)
__out_bcount_part_opt(size,length)
__out_ecount(size)
__out_ecount_full(size)
__out_ecount_full_opt(size)
__out_ecount_opt(size)
__out_ecount_part(size,length)
__out_ecount_part_opt(size,length)
__out_opt

 アドバンスド注釈(Advanced annotations)(msdnでは「詳細な注釈」と訳されています)はパラメータや戻り値に関する追加的な情報を提供します。それぞれのパラメータや戻り値はゼロまたは1つのアドバンスド注釈を使います。

AnnotationDescription
__blocksOn(resource) 指定されたリソースのファンクションブロック(functions blocks)
__callback 関数のポインタとして使うことのできる関数(コールバック関数を表現するために用いられると思われます)
__checkReturn 呼び出し側は戻り値をチェックしなければなりません
__format_string printfスタイルの %マーカーを持つパラメータ
__in_awcount(expr,size) exit時にexprが真の場合、入力バッファのサイズがバイト数で示されます。exprが偽の場合サイズは要素数で示されます。
__nullnullterminated 2つのNULLで終端されたバッファ。
__nullterminated NULLで終端されたバッファ。
__out_awcount(expr, size) exit時点でexprが真の場合、出力バッファのサイズはバイト数で示され、偽の場合要素すうで示されます。
__override 仮想メソッドのためにC#スタイルのオーバライドの振る舞いを指定します。
__reserved このパラメータが将来の利用に備えてreservedであることを示します。このパラメータはNULLまたはゼロでなければなりません。
__success(expr) exit時点でexprが真の場合、呼び出し側は別の注釈によって指定を信頼することができ、偽の場合信頼することができません。この注釈はHRESULT値を返す関数に自動的に追加されます。
__typefix(ctype) パラメータを宣言されたタイプではなく、指定されたタイプとして扱います。

 C言語では(通常は)main関数がプログラムのエントリポイントとなりますが、 システムによってmain関数が呼ばれるまで(とmain関数の後始末)は「ランタイムライブラリ」と呼ばれるライブラリによって暗黙のうちに処理されることが多いです。Visual Studioでも多様なランタイムライブラリが提供されますが、これらのライブラリが「ランタイム化」によって何を実現しているのか、msdnのドキュメントではあまり体系的には述べられていないようです。

 Cランタイム(CRT)ライブラリは次の条件の違いによるいくつかのバージョンがあります。

  • 静的リンク用と動的リンク用
  • デバッグ用とリリース用

 現在は、すべてのCRTライブラリがマルチスレッドに対応しています。

▼ Property
記事情報
datePublished2011-01-01
dateModified2018-06-20
authorアセンブラの魔女
headlineVisual C++関連記事のページです
keywordsVisual C++
keywordsWindows
publisher name= wiredFish, logo.name= wiredFish, logo.url= https://books-nekoya.jp/Programming/chigu-hagu-title-01.png size= 208 pixel x 50 pixel
image.url url= https://books-nekoya.jp/Programming/chigu-hagu-title-01.png , size= 208 pixel x 50 pixel