C プラグマ 新しいページはコチラ
提供: yonewiki
(→#pragma comment(linker, [” ”])) |
(→#pragma once) |
||
1行: | 1行: | ||
+ | [[C PlusPlus#Cにもあった技術|C++]]へ戻る | ||
+ | |||
+ | |||
※このページではC言語にも存在していたという意味で記事タイトルがC プラグマになっていますが、<br /> | ※このページではC言語にも存在していたという意味で記事タイトルがC プラグマになっていますが、<br /> | ||
[[C PlusPlus|C++]]でも同様です。[[C PlusPlus|C++]]だけの機能がある場合は明記します。<br /> | [[C PlusPlus|C++]]でも同様です。[[C PlusPlus|C++]]だけの機能がある場合は明記します。<br /> | ||
18行: | 21行: | ||
=='''#pragma'''== | =='''#pragma'''== | ||
+ | |||
<nowiki>#</nowiki>pragmaディレクティブは半角スペースに続けてもう一つのワードと引数パラメータを伴って定義する形式のものがほとんどです。また、マイクロソフト固有の仕様ですが、<nowiki>#</nowiki>pragmaの代わりに__pragmaでも同様の機能として動作するようになっています。これはディレクティブとして先頭に使われる#以降の#はプリプロセッサ演算子の文字列化演算子として扱われることを回避するために用意されています。 | <nowiki>#</nowiki>pragmaディレクティブは半角スペースに続けてもう一つのワードと引数パラメータを伴って定義する形式のものがほとんどです。また、マイクロソフト固有の仕様ですが、<nowiki>#</nowiki>pragmaの代わりに__pragmaでも同様の機能として動作するようになっています。これはディレクティブとして先頭に使われる#以降の#はプリプロセッサ演算子の文字列化演算子として扱われることを回避するために用意されています。 | ||
110行: | 114行: | ||
があります。それぞれについても以下に説明します。 | があります。それぞれについても以下に説明します。 | ||
+ | |||
+ | |||
+ | |||
====#pragma comment(compiler)==== | ====#pragma comment(compiler)==== | ||
131行: | 138行: | ||
となるような、ASCIIコードが挿入されました。.objファイルはバイナリーファイルですので、ASCIIコードとして読み取れる部分とそうでない部分とが混在するファイルになっています。 | となるような、ASCIIコードが挿入されました。.objファイルはバイナリーファイルですので、ASCIIコードとして読み取れる部分とそうでない部分とが混在するファイルになっています。 | ||
+ | |||
+ | |||
+ | |||
====#pragma comment(linker, [” ”])==== | ====#pragma comment(linker, [” ”])==== | ||
137行: | 147行: | ||
*<nowiki>#</nowiki>pragma comment(linker, ”/INCLUDE:[]”) | *<nowiki>#</nowiki>pragma comment(linker, ”/INCLUDE:[]”) | ||
+ | :シンボル参照の強制と同じ動作で、シンボル(関数名)を記述するとシンボルテーブルに追加されます。これはプログラム中で使われないような関数をリンカが無視するのを防いで、実行可能ファイルからとりこむような処理です。 | ||
+ | |||
+ | |||
*<nowiki>#</nowiki>pragma comment(linker, ”/DEFAULTLIB:[]”) | *<nowiki>#</nowiki>pragma comment(linker, ”/DEFAULTLIB:[]”) | ||
+ | :リンク処理時のライブラリの参照を指定します。優先度はコマンドライン→/DEFAULTLIB→実行可能ファイル(.obj)内に記述されたライブラリ参照の順で参照され、/NODEFAULTLIBによるライブラリ参照の無視に関する指示が優先されます。/NODEFAULTLIB関連の指示が優先されることから、これらのライブラリ参照の指示によらず、外部に依存していないリンク処理になっていることを確実にすることができます。 | ||
+ | |||
+ | |||
*<nowiki>#</nowiki>pragma comment(linker, ”/EXPORT:[]”) | *<nowiki>#</nowiki>pragma comment(linker, ”/EXPORT:[]”) | ||
− | + | :プログラムから関数を出力して、他のファイルから関数を利用できるようにするものです。 | |
− | *<nowiki>#</nowiki>pragma comment(linker, ”/ | + | :実際には |
+ | :<nowiki>#</nowiki>pragma comment(linker, ”/EXPORT:関数名(@1~65536の値(省略可),NONAME(省略可),DATA(省略可))”) | ||
+ | :という具合に利用します。1~65536の値は関数に割り振られる番号で省略すると、リンク処理時に自動で割り付けられます。NONAMEと指定すると関数名を省略した1~65535の番号によって呼び出す関数となります。DATAを使うとデータとして取り扱われます。 | ||
+ | :関数の出力はプログラムソースに__declspec(dllexport)キーワードを付けて出力する方法や.defファイルにEXPORT命令を使う方法もあります。なんだか意味不明な説明に感じると思いますが、ここではDLLのような外部から呼び出される関数やデータを作成する場合に使うプラグマがあると覚えておけばよいと思います。詳細は別の項目で記述するつもりです。 | ||
+ | |||
+ | |||
+ | *<nowiki>#</nowiki>pragma comment(linker, ”\"/MANIFESTDEPENDENCY:[]\"”) | ||
+ | :マニフェストの依存関係についての記述をします。マニフェストとは声明文のような意味を持つイタリア語ですが、マイクロソフトではこのまにゅフェストと呼ばれる仕組みでClickOnceアプリケーションと呼ばれる自己更新型のアプリケーションを作成するための技術として用意されているものです。マニフェストはXMLによる構文でいくつかの要素を記述することになっていますが、このMANIFESTDEPENDENCYという要素にはアプリケーションのバージョンに関する情報を記述することになっています。詳細な情報については、ここで簡単に説明できるようなものではないので、これも別の場所で説明したいと思います。 | ||
+ | |||
+ | |||
*<nowiki>#</nowiki>pragma comment(linker, ”/SECTION:[]”) | *<nowiki>#</nowiki>pragma comment(linker, ”/SECTION:[]”) | ||
+ | :リンク処理ではセクションと呼ばれる単位で関数が配置されます。VxD(Virtual x device Driver:仮想デバイスドライバ OSと同じレベルの権限をもつ制御プログラム)の開発では、このようなセクションで分割される実行ファイルの配置を制御してメモリの使い方を厳密に指定する必要がある場合があります。SECTIONでは以下のよう定義することで、セクションの属性を変更することができます。 | ||
+ | |||
+ | :<nowiki>#</nowiki>pragma comment(linker, ”/SECTION:セクション名,(!)セクション属性記号,ALIGN=#2の累乗で表現される値(省略可)”) | ||
+ | |||
+ | :このような動作を理解するにはリンク処理がどのようなものなのかを理解する必要がありますので、理解を深めるにはリンク処理を何度も実行して、セクションの生成のされかたや、デフォルトで定義されるセクションとROM配置やRAM配置の法則を知っていく必要があります。もしく同様の解説をしてくれる文献やサイトに触れる必要があります。ここでは説明しきれませんし、いまのところ自分もそれほど詳しくはありません。ROMやRAMの配置まで意識する必要があるときに使うものだと知っていれば十分だと思います。自分自身も理解を進めた場合には追加の記事を作成したいと思います。 | ||
+ | |||
+ | |||
+ | *<nowiki>#</nowiki>pragma comment(linker, ”/MERGE:[]”) | ||
+ | :上記のセクションに関する指示と同様にリンク処理よって生成されるセクションを統合させる処理です。例えば、以下のように使います。 | ||
+ | |||
+ | :<nowiki>#</nowiki>pragma comment(linker, ”/MERGE:統合するセクション名1=統合するセクション名2(統合後のセクション名でもある)”) | ||
+ | |||
+ | :とします。 | ||
+ | |||
+ | |||
+ | リンク処理の解析は機械語を読み解くのと同様に複雑ですが、動作自体は簡単な処理だと言われています。なんだかよくわからない処理がなされているように思われがちなリンク処理ですが、法則を理解出来れば、もっと理解が深まるということだと思います。 | ||
+ | |||
+ | |||
====#pragma comment(user, [” ”])==== | ====#pragma comment(user, [” ”])==== | ||
151行: | 194行: | ||
'''<nowiki>#</nowiki>pragma comment(user, ”コメント(ASCIIコード範囲の文字利用を推奨)”)''' | '''<nowiki>#</nowiki>pragma comment(user, ”コメント(ASCIIコード範囲の文字利用を推奨)”)''' | ||
+ | |||
+ | |||
+ | |||
+ | |||
===#pragma once=== | ===#pragma once=== | ||
+ | <nowiki>#</nowiki>includeのようなソース読み込み指示によって、ソースファイルが重複してオープンされないように制御するためのプラグマです。プロジェクトに使われるヘッダファイルとメインソースコードファイルの全てに追加しておくべきプラグマです。以下のマクロと同等だと考えてよいです。 | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | FILE sample.h | ||
+ | #ifndef __SAMPLE.H__ | ||
+ | #define __SAMPLE.H__ | ||
+ | |||
+ | ヘッダファイルプロトタイプ宣言 | ||
+ | |||
+ | #endif | ||
+ | </syntaxhighlight> | ||
+ | 上記のようなマクロでは、インクルードガードと呼ばれる手法を使っていると呼ばれていて、一度ヘッダファイルを読み込むとファイル名ごとに決められたマクロ名が定義され、2回目にヘッダファイルが呼び出された時にはマクロが定義されているため、#ifndefの条件が成立せず、重複して読み込まれないようになります。 | ||
+ | |||
+ | |||
+ | 上記のようなインクルードガードを簡潔にするのが、#pragma onceです。処理系によってこのプラグマは使えないものもありますが、最近のコンパイラでは広く適用できるプラグマになっているので、汎用性が高まると思います。 | ||
+ | |||
+ | |||
+ | 上記マクロを以下のようにプラグマを使って、すっきりと記述できます。 | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | FILE sample.h | ||
+ | #pragma once | ||
+ | ヘッダファイルプロトタイプ宣言 | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | 但し、この方法は標準化されたものではないため、Microsoft Visual Studio C++ 4.0以上でしか動作しないと考えて扱っても良いのかもしれません。他のコンパイラでも動作するものもありますが、自分の環境に合わせてしまっても良いと思います。他の人に配るなら、 | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | FILE sample.h | ||
+ | #ifndef __SAMPLE.H__ | ||
+ | #define __SAMPLE.H__ | ||
+ | |||
+ | #if _MSC_VER > 1000 | ||
+ | #pragma once | ||
+ | #endif | ||
+ | ヘッダファイルプロトタイプ宣言 | ||
+ | |||
+ | #endif | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | のように記述すると良いと思います。インクルードガードによる手法をサポートしつつも、#pragma onceの機能も有効利用できます。コンパイル速度が#pragma onceの方が早いので、おすすめです。他のコンパイラでも速度が速くなるようにインクルードガードを実現するには、冗長インクルードガードと呼ばれる手法を使います | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | #ifndef __SAMPLE.H__ | ||
+ | #include "sample.h" | ||
+ | #endif | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | のようにしてインクルードガード下上でさらにインクルード分のところでも読み込むかどうかを判断する処理を加えます。インクルード部がかなり煩雑になりますが、2重に読み込むことをより早い段階で避けることが出来るので、コンパイル速度の向上が見込めます。 | ||
+ | |||
+ | |||
+ | [[C PlusPlus#Cにもあった技術|C++]]へ戻る |