[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.2 グローバル宣言と VMS

GCC は、VAX-C のキーワード globalrefglobaldefglobalvalue を提供していない。GAS、GNU アセンブラの 隠し機能を使うと同じ効果を得られる。以下のマクロにより、 この機能を正当で自然な方法で使うことができる。

 
#ifdef __GNUC__
#define GLOBALREF(TYPE,NAME)                      \
  TYPE NAME                                       \
  asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME)
#define GLOBALDEF(TYPE,NAME,VALUE)                \
  TYPE NAME                                       \
  asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME) \
    = VALUE
#define GLOBALVALUEREF(TYPE,NAME)                 \
  const TYPE NAME[1]                              \
  asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)
#define GLOBALVALUEDEF(TYPE,NAME,VALUE)           \
  const TYPE NAME[1]                              \
  asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)  \
    = {VALUE}
#else
#define GLOBALREF(TYPE,NAME) \
  globalref TYPE NAME
#define GLOBALDEF(TYPE,NAME,VALUE) \
  globaldef TYPE NAME = VALUE
#define GLOBALVALUEDEF(TYPE,NAME,VALUE) \
  globalvalue TYPE NAME = VALUE
#define GLOBALVALUEREF(TYPE,NAME) \
  globalvalue TYPE NAME
#endif

(名前の前のプレフィックス _$$PsectAttributes_GLOBALSYMBOL は、 シンボルの属性が修正された後で、GAS により消去される。) これらのマクロは、VMS 用バイナリ配布中のヘッダファイル ‘GNU_HACKS.H’ で提供されている。使い方の例を以下に示す。

 
GLOBALREF (int, ijk);
GLOBALDEF (int, jkl, 0);

マクロ GLOBALREFGLOBALDEF は配列に対しては 単純には使えない。配列の次元を宣言の中の正しい位置に置く方法が ないからである。ただし、まず配列型に対して typedef を定義しておけば これらのマクロを使って配列を宣言することができる。以下のようにする。

 
typedef int intvector[10];
GLOBALREF (intvector, foo);

配列や構造体の初期化子もこのマクロでは使えない。初期化子をそれ自身 マクロとして定義するか、GLOBALDEF マクロを手で展開することは 可能である。GLOBALREF マクロを大きな配列に対して使いたいが、 その配列の各要素を明示的に初期化する必要はないという場合もあるだろう。 その場合、{0,} という形の初期化子を使うこともできる。 これは配列全体を 0 に初期化する。

この実装の問題は、GLOBALVALUEREFGLOBALVALUEDEF で 宣言した変数が常に配列になってしまうことである。例えば、

 
GLOBALVALUEREF(int, ijk);

と宣言すると、変数 ijkint [1] 型の配列として 宣言する。globalvalue が実際には定数なのでこうなる。 その「値」はリンカが普通はアドレスと考えるものである。これは、 C の整数値の動作ではなく、配列の動作である。このため、 このシンボルを配列名として取り扱うと一貫した結果が得られる。 その値が間違った型を持つように見えるという点を除けば。 この配列の要素を参照しようとしてはいけない。 これは要素はなにも持っていないのである。配列の「アドレス」は 実際の記憶域のアドレスではないかもしれないのである。

シンボルが配列であるという事実は、その変数が使われたときに警告が 出るという可能性につながる。警告を避けるには型キャストを挿入すること。 以下に例を示す。マクロ展開の中にマクロ名自身と同じ名前を 使っても良いという ANSI C の機能を活かしている。

 
GLOBALVALUEREF (int, ss$_normal);
GLOBALVALUEDEF (int, xyzzy,123);
#ifdef __GNUC__
#define ss$_normal ((int) ss$_normal)
#define xyzzy ((int) xyzzy)
#endif

列挙型である変数に対して globaldefglobalref を 使ってはいけない。実装されていないからである。代わりに、 その変数を整数とし、列挙値のそれぞれに globalvaluedef を使うこと。 例は以下のようになる。

 
#ifdef __GNUC__
GLOBALDEF (int, color, 0);
GLOBALVALUEDEF (int, RED, 0);
GLOBALVALUEDEF (int, BLUE, 1);
GLOBALVALUEDEF (int, GREEN, 3);
#else
enum globaldef color {RED, BLUE, GREEN = 3};
#endif

This document was generated using texi2html 1.78.