[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ] [ DOC Home ]

# 11DEC C RTLの64ビット・アドレッシング・サポート

本章はOpenVMS Alphaバージョン7.0以降のDEC Cランタイム・ライブラリで提供される 64ビット・アドレッシング・サポートについて説明します。

DEC Cランタイム・ライブラリは， 64ビット・ポインタをサポートする際に以下の特徴があります。

- 既存のプログラムのバイナリおよびソースの互換性を保証する。

- 64ビット・サポートを利用するよう修正されていないアプリケーションには影響がない。

- 64ビット・メモリを割り当てるメモリ割り当てルーチンが強化された。

- 64ビット・ポインタに対応するために関数パラメータが拡張された。

- 呼び出し側が使用しているポインタ・サイズを知る必要がある関数について， 2種類の実装を用意する。

- シームレスに正しいインプリメンテーションを呼び出すための新しい情報が， DEC Cバージョン5.2以降のコンパイラに用意されている。

- 32ビット形式のポインタ・サイズと 64ビット形式のポインタ・サイズが混在しているアプリケーションに対して， 32ビット形式または64ビット形式の関数を明示的に呼び出すことができる。

- 32ビット・アプリケーションと64ビット・アプリケーションで 1つの共用イメージを使用できる。

# 11.1DEC Cランタイム・ライブラリの使用

OpenVMS Alphaバージョン7.0以降のDEC Cランタイム・ライブラリは， 64ビット・ポインタを生成し，受け取ることができます。 64ビット・ポインタを使用する第2のインタフェースを必要とする関数は， 対応する32ビットと同じオブジェクト・ライブラリおよび共用イメージにあります。 オブジェクト・ライブラリや共用イメージが新しく作成されることはありません。 64ビット・ポインタを使用することで， リンク・コマンドやリンク・オプション・ファイルに変更を加える必要はありません。

DEC C 64ビット環境を使用すると，1つのアプリケーションの中で 32ビット・アドレスと64ビット・アドレスの両方を使用できます。 ポインタ・サイズの操作についての詳細は， 『DEC C User's Guide for OpenVMS Systems』の /POINTER_SIZE修飾子，および `#pragma pointer_size` または `#pragma required_pointer_size` プロセッサ・ディレクティブに関する記述を参照してください。

/POINTER_SIZE修飾子に対して，ユーザは値32または64を指定します。 ここで指定した値は， コンパイル・ユニットの中の省略時の設定のポインタ・サイズとして使用されます。 アプリケーション・プログラマは，あるモジュール・セットは 32ビット・ポインタを使用して，また別のセットは 64ビット・ポインタを使用してコンパイルします。この 2つのモジュール・グループがお互いを呼び出す場合，特に注意しなければなりません。

/POINTER_SIZE修飾子の使用は，DEC C RTLヘッダ・ファイルの処理にも影響します。 32ビット実装および64ビット実装を持つ関数の場合， 修飾子に指定される実際の値に関わらず，/POINTER SIZE修飾子によって関数プロトタイプは両方の関数にアクセスできます。さらに， 修飾子に指定される値は， コンパイル・ユニットの中で呼び出す省略時の設定の実装を決定します。

`#pragma pointer_size` および `#pragma required_pointer_size`プロセッサ・ディレクティブは， コンパイル・ユニットの中で使用されるポインタ・サイズを変更します。 32ビット・ポインタを省略時の設定のポインタとし，モジュール内の特定のポインタを 64ビット・ポインタとして宣言することができます。 64ビット・メモリ領域からメモリを取得するために，`malloc` の `_malloc64` 形式を呼び出す必要があります。

# 11.2メモリを指す 64ビット・ポインタの取得

DEC C RTLには， 新しく割り当てられたメモリへのポインタを返す関数が数多くあります。 これらの各関数の中で，アプリケーションは指されているメモリを所有し， そのメモリを解放する責任があります。

メモリを割り当てる関数は次に示します。 `malloc`
`calloc`
`realloc`
`strdup` 各関数とも32ビット実装および64ビット実装を持ちます。 /POINTER SIZE修飾子が使用される場合，次の関数が呼び出される可能性もあります。 `_malloc32` , `_malloc64`
`_calloc32` , `_calloc64`
`_realloc32` , `_realloc64`
`_strdup32` , `_strdup64` /POINTER_SIZE=32が指定されると，すべての`malloc` 呼び出しの省略時の設定は`_malloc32` になります。

/POINTER_SIZE=64が指定されると，すべての`malloc` 呼び出しの省略時の設定は`_malloc64` になります。

アプリケーションが32ビットまたは 64ビットのどちらのメモリ割り当てルーチンを呼び出した場合も， `free` 関数があります。 この関数はどちらのサイズのポインタも受け取ります。

メモリ割り当て関数は，64ビット・メモリへのポインタを返す唯一の関数です。 (FILE，WINDOW，DIRなどのように)呼び出しアプリケーションに返されるすべての DEC C RTL構造ポインタは，通常は32ビット・ポインタです。このため32ビットと 64ビットの両方の呼び出し側とも， アプリケーションの中でこれらの構造ポインタを渡すことができます。

# 11.3DEC Cヘッダ・ファイル

DEC Cバージョン5.2以降で提供するヘッダ・ファイルは， 64ビット・ポインタをサポートします。ポインタを含む各関数プロトタイプは， 受け取るポインタのサイズを示すように構成されています。

32ビット・ポインタまたは64ビット・ポインタのいずれか 1つを引数として受け取る関数に対して， 32ビット・ポインタをその引数として渡すことができます。

しかし，32ビット・ポインタを受け取る関数への引数として， 64ビット・ポインタを渡すことはできません。この操作を試みると， コンパイラによって診断が行われ，MAYLOSEDATAメッセージが表示されます。なお， IMPLICITFUNC診断メッセージが表示された場合，これは，その関数の呼び出しについて， ポインタ・サイズのチェックをこれ以上実行できないことを表します。

特に有効なポインタ・サイズについてのコンパイラの診断メッセージを次に示します。

- %CC-IMPLICITFUNC

  指定された関数の使用に先立ち，関数プロトタイプが見つからないことを表します。 コンパイラおよびランタイム・システムは，プロトタイプ定義に基づいて， 不適切なポインタ・サイズの使用を検出します。 正しいヘッダ・ファイルがインクルードできないと，不適切な結果が生じたり， ポインタの切り捨てが発生する可能性があります。

- %CC-MAYLOSEDATA

  この操作を実行するには切り捨てが必要であることを表します。この操作では， 指定されたコンテキストの中で64ビット・ポインタをサポートしない関数に対して， 64ビット・ポインタを渡している可能性があります。または関数の戻り値は 64ビット・ポインタを返し，ソースはその戻り値を 32ビット・ポインタに保存しようとしている可能性があります。

- %CC-MAYHIDELOSS

  (有効な場合)このメッセージは，キャスト操作により表示が抑止されている本当の MAYLOSEDATAメッセージを出力することを可能にします。

# 11.4影響のある関数

OpenVMS Alphaバージョン7.0が提供するDEC C RTLは， 32ビット・ポインタだけを使用するアプリケーション， 64ビット・ポインタだけを使用するアプリケーション， または両方を組み合わせて使用するアプリケーションにそれぞれ適応します。 64ビット・メモリを使用するには， 少なくともアプリケーションの再コンパイルと再リンクが必要です。 ソース・コードの変更量は，アプリケーション， ほかのランタイム・ライブラリへの呼び出し， 使用されているポインタ・サイズの組み合わせによってそれぞれ異なります。

DEC C RTL関数は，次の4種類に分類できます。

- ポインタ・サイズの選択に影響を受けない関数

- どちらのポインタ・サイズも受け取れるよう拡張された関数

- 32ビット実装と64ビット実装を持つ関数

- 32ビット・ポインタだけを受け取る関数

アプリケーション開発者の立場からすると，上記の最初の 2つの関数は単一ポインタ・モードと混合ポインタ・モードのいずれの場合も簡単に使用できます。

3番目の関数は， 単一ポインタ・モードで使用している場合はソース・コードを変更する必要はありません。 ただし混合ポインタ・モードで使用している場合は，ソース・コードの変更が必要です。

4番目の関数は，64ビット・ポインタを使用している場合は十分な注意が必要です。

## 11.4.1ポインタ・サイズの影響がない関数

プロトタイプにポインタに関連するパラメータや戻り値が含まれていない場合， ポインタ・サイズの選択による関数への影響を考慮する必要はありません。 算術関数がこれに相当します。

この種類の関数のうち，プロトタイプにポインタを含まない関数は， ポインタ・サイズの選択による影響はありません。たとえば `strerror` 関数のプロトタイプは次のとおりです。

         char * strerror (int error_number);

この関数は文字列へのポインタを返しますが，この文字列は DEC C RTLで割り当てられます。その結果，32ビット・アプリケーションと 64ビット・アプリケーションを両方ともサポートするために，この種類のポインタは， 32ビット・ポインタに対応することが常に保証されています。

## 11.4.2両方のポインタ・サイズを受け取る関数

Alphaアーキテクチャは64ビット・ポインタをサポートします。 OpenVMS Alpha呼び出し規則では，すべての引数が 64ビット値として渡されることを指定しています。 OpenVMS Alpha Version 7.0 より前のバージョンでは，プロシージャに渡される32ビット・アドレスはすべて， 64ビット・パラメータに符号拡張されていました。呼び出された関数はパラメータを 32ビット・アドレスとして宣言し，これによってコンパイラは32ビット命令(LDLなど) を生成して，これらのパラメータを処理していました。

DEC C RTL内の関数の多くは拡張され， 64ビット・アドレス全体を受け取るようになりました。関数`strlen` を例に考えます。

         size_t strlen (const char *string);

この関数内の唯一のポインタは文字列ポインタです。ユーザが 32ビット・ポインタを渡すと，関数は符号拡張された64ビット・アドレスで動作します。 ユーザが64ビット・アドレスを渡すと，関数はそのアドレスで直接動作します。

DEC C RTLは引き続き，この種類の関数に対して， 1つのエントリ・ポイントだけを持ちます。この種類の関数の 4つのポインタ・サイズ・オプションのいずれを追加する場合も， ソース・コードの変更は必要ありません。OpenVMSマニュアルでは， これらの関数を64ビット・フレンドリと呼びます。

## 11.4.32種類の実装を持つ関数

多くの理由から，関数は，32ビット・ポインタ用と64ビット・ポインタ用に 2種類の実装を持つ必要があります。その理由を次に示します。

- 戻り値のポインタ・サイズは，引数の1つのポインタ・サイズと同じです。 引数が32ビットの場合，戻り値は32ビットです。引数が64ビットの場合， 戻り値は64ビットです。

- 引数の1つはオブジェクトへのポインタですが， そのオブジェクトのサイズがポインタ・サイズに影響を受けます。 指しているバイト数を知るためには，コードが32ビット・ポインタ・サイズ・モードと 64ビット・ポインタ・サイズ・モードのどちらでコンパイルされたのかを知る必要があります。

- 関数は動的に割り当てられたメモリのアドレスを返します。メモリは 32ビット・ポインタでコンパイルされた場合は32ビット空間に割り当てられ， 64ビット・ポインタでコンパイルされた場合は64ビット空間に割り当てられます。

アプリケーション開発者の立場から見ると，これらの各関数にはそれぞれ 3種類の関数プロトタイプがあります。`<string.h>` ヘッダ・ファイルは， その戻り値が先頭引数のポインタ・サイズに依存する多くの関数を持ちます。 `memset` 関数を例に考えます。ヘッダ・ファイルは， この関数に対して3つのエントリ・ポインタを定義します。

         void * memset   (void *memory_pointer, int character, size_t size);
         void *_memset32 (void *memory_pointer, int character, size_t size);
         void *_memset64 (void *memory_pointer, int character, size_t size);

最初のプロトタイプは，この関数を使用している場合に， アプリケーションが現在呼び出している関数です。コンパイラは`memset` への呼び出しを， /POINTER_SIZE=32でコンパイルされているときは `_memset32` への呼び出しに，また， /POINTER_SIZE=64コンパイルされているときは `_memset64` 呼び出しにそれぞれ置換します。

関数の32ビット形式または64ビット形式を直接呼び出すことにより， この省略時の設定の動作を変更することができます。これにより /POINTER_SIZE修飾子で指定した省略時の設定のポインタ・サイズに関係なく， ポインタ・サイズが混在しているアプリケーションに対応できます。

/POINTER_SIZE修飾子を指定せずにコンパイルしている場合， 32ビット固有のインタフェース関数プロトタイプも， 64ビット固有のインタフェース関数プロトタイプも定義されないことに注意してください。 この場合コンパイラは，2種類の実装を持つインタフェースに対して，自動的に 32ビット・インタフェースを呼び出します。

DEC C RTLでの64ビット・ポインタ・サイズのサポートの一環として， 2種類の実装を持つ関数の一覧を 表 11-1に示します。 /POINTER_SIZE修飾子を指定してコンパイルしている場合， 修正されていない関数名を呼び出すと， その修飾子で指定されるポインタ・サイズに対応するインタフェースが呼び出されます。

### 表 11-1 2種類の実装を持つ関数

`basename` | `malloc` | `strpbrk` | `wcsncat`
`bsearch` | `mbsrtowcs` | `strptime` | `wcsncpy`
`calloc` | `memccpy` | `strrchr` | `wcspbrk`
`catgets` | `memchr` | `strsep` | `wcsrchr`
`ctermid` | `memcpy` | `strstr` | `wcsrtombs`
`cuserid` | `memmove` | `strtod` | `wcsstr`
`dirname` | `memset` | `strtok` | `wcstok`
`fgetname` | `mktemp` | `strtol` | `wcstol`
`fgets` | `mmap` | `strtoll` | `wcstoul`
`fgetws` | `qsort` | `strtoq` | `wcswcs`
`fullname` | `realloc` | `strtoul` | `wmemchr`
`gcvt` | `rindex` | `strtoull` | `wmemcpy`
`getcap` | `strcat` | `strtouq` | `wmemmove`
`getcwd` | `strchr` | `tgetstr` | `wmemset`
`getname` | `strcpy` | `tmpnam` |
`gets` | `strdup` | `wcscat` |
`index` | `strncat` | `wcschr` |
`longname` | `strncpy` | `wcscpy` |

## 11.4.432ビット・ポインタに制限されている関数

DEC C RTLには64ビット・ポインタをサポートしない関数もあります。 64ビット・ポインタをサポートしない関数に64ビット・ポインタを渡そうとすると， コンパイラは%CC-W-MAYLOSEDATA警告メッセージを生成します。 /POINTER_SIZE=64修飾子を指定してコンパイルしたアプリケーションは， 64ビット・ポインタをサポートしない関数に 64ビット・ポインタを渡すことがないように， ソース・コードの修正が必要な場合があります。

32ビット・ポインタしか使用できない関数を 表 11-2に示します。 DEC C RTLは，これらの関数に対して64ビット・サポートを提供していません。

### 表 11-2 32 ビット・ポインタに制限されている関数

`atexit` | `getopt` | `modf` | `setstate`
`execve` | `iconv` | `recvmsg` | `setvbuf`
`execvp` | `initstate` | `sendmsg` |
`frexp` | `ioctl` | `setbuf` |

関数呼び出し処理の一部として， ユーザが提供する関数へのコールバックを行う関数の一覧を 表 11-3に示します。 コールバック・プロシージャに64ビット・ポインタが渡されることはありません。

### 表 11-3 32ビット・ポインタだけを渡すコールバック

`from_vms` | `to_vms`
`ftw` | `tputs`

# 11.5ヘッダ・ファイルの読み込み

この節では，DEC C RTLヘッダ・ファイルで使用されるポインタ・サイズ操作について説明します。 次の例を参考にヘッダ・ファイルを読み， 必要に応じてヘッダ・ファイルを修正してください。

### 例

1.     :
       #if INITIAL__POINTER_SIZE 【1】
       #   if (VMS__VER < 70000000) || !defined __ALPHA 【2】
       #      error " Pointer size usage not permitted before OpenVMS Alpha V7.0"
       #   endif
       #   pragma __pointer_size __save 【3】
       #   pragma __pointer_size 32 【4】
       #endif
       :
       :
       #if __INITIAL_POINTER__SIZE 【5】
       #   pragma __pointer_size 64
       #endif
       :
       :
       #if __INITIAL_POINTER_SIZE 【6】
       #   pragma __pointer_size __restore
       #endif
       :

   /POINTER_SIZE修飾子をサポートするすべてのDEC Cコンパイラは，あらかじめマクロ `__INITIAL_POINTER_SIZE` を定義しています。 このマクロが定義されていない場合，DEC C RTLヘッダ・ファイルは， 暗黙値0を使用するというANSI規則を利用します。

   /POINTER_SIZE修飾子が使用される場合，マクロは32または64として定義されます。 この修飾子が使用されない場合は，0として定義されます。 【1】の文は， "ユーザがコマンド・ラインで/POINTER_SIZE=32 または/POINTER_SIZE=64 を指定した場合"という意味です。

   DEC Cバージョン5.2以降は，多くのOpenVMSプラットフォームでサポートされます。 コンパイルのターゲットが64ビット・ポインタをサポートしない場合， 【2】の行はエラー・メッセージを生成します。

   ヘッダ・ファイルは，このヘッダがインクルードされる時点では， 作用する実際のポインタ・サイズ・コンテキストを決定することができません。 さらに，DEC Cコンパイラは，`__INITIAL_POINTER_SIZE` マクロと， ポインタ・サイズを変更するメカニズムだけを提供し， 現在のポインタ・サイズを決定することはしません。

   ポインタ・サイズに依存するヘッダ・ファイルはすべて，ポインタ・サイズ・コンテ キストの保存【3】，初期化【4】，変更【5】，および復元【6】を行う必要があります。

2.     :
       #ifndef __CHAR_PTR32 【1】
       #   define __CHAR_PTR32 1
           typedef char * __char_ptr32;
           typedef const char * __const_char_ptr32;
       #endif
       :
       :
       #if __INITIAL_POINTER__SIZE
       #   pragma __pointer_size 64
       #endif
       :
       :
       #ifndef __CHAR_PTR64 【2】
       #   define __CHAR_PTR64 1
           typedef char *__ char_ptr64;
           typedef const char * __const_char_ptr64;
       #endif
       :

   64ビット・ポインタ・サイズ・コンテキストの中で， 32ビット・ポインタを参照する必要がある関数プロトタイプがあります。また， 32ビット・ポインタ・サイズ・コンテキストの中で， 64ビット・ポインタを参照する必要がある関数プロトタイプもあります。

   DEC Cコンパイラは，`typedef` が作成される時点で， `typedef` で使用されるポインタ・サイズを結合させます。 `__char_ptr32` の`typedef` 宣言【1】は 32ビット・コンテキストで行われます。 `__char_ptr64`の `typedef` 宣言【2】は64ビット・コンテキストで行われます。

3.     :
       #if INITIAL__POINTER_SIZE
       #   if (__VMS_VER < 70000000) || !defined __ALPHA
       #      error " Pointer size usage not permitted before OpenVMS Alpha V7.0"
       #   endif
       #   pragma __pointer_size save
       #   pragma __pointer_size 32
       #endif
       :
       【1】
       :
       #if __INITIAL_POINTER_SIZE 【2】
       #   pragma __pointer_size 64
       #endif
       :
       【3】
       :
       int abs (int __j);【4】
       :
       __char_ptr32 strerror (int __errnum);【5】
       :

   64ビット・ポインタをサポートする関数プロトタイプの宣言の前に， ポインタ・コンテキストが32ビット・ポインタから 64ビット・ポインタに変更されています【2】。

   32ビット・ポインタに制限されている関数は，ヘッダ・ファイルの 32ビット・ポインタ・コンテキスト・セクション【1】に配置されています。 ほかの関数はすべて，ヘッダ・ファイルの 64ビット・ポインタ・コンテキスト・セクション【2】に配置されています。

   ポインタ・サイズの影響を受けない関数(【4】および【5】)は， 64ビット・セクションに配置されています。これらの関数は 32ビット・アドレスの戻り値を除き，ポインタ・サイズの影響は受けません【5】。 またこれらの関数は64ビット・セクションにあり，前述の32ビット固有の `typedef`を使用します。

4.     :
       #if __INITIAL_POINTER_SIZE
       #   pragma __pointer_size 64
       #endif
       :
       :
       #if __INITIAL_POINTER_SIZE == 32 【1】
       #   pragma __pointer_size 32
       #endif
       :
       char *strcat (char *__s1, __const_char_ptr64 __s2); 【2】
       :
       #if __INITIAL_POINTER_SIZE
       #   pragma __pointer_size 32
           :
           char *_strcat32  (char *__s1, __const_char_ptr64 __s2); 【3】
           :
       #   pragma __pointer_size 64
           :
           char *_strcat64  (char *__s1, const char *__s2); 【4】
           :
       #endif
       :

   この例は，32ビット実装と64ビット実装の両方を持つ関数に対する宣言です。 これらの宣言は，ヘッダ・ファイルの64ビット・セクションに配置されています。

   関数の通常の宣言【2】は， /POINTER_SIZE修飾子で指定したポインタ・サイズを使用して行われます。 ヘッダ・ファイルが64ビット・ポインタ・コンテキストにあり， 【1】に文を指定しているため，【2】の宣言は /POINTER_SIZE修飾子と同じポインタ・サイズ・コンテキストを使用して行われます。

   32ビット固有のインタフェース【3】および 64ビット固有のインタフェース【4】は， 32ビット・ポインタ・サイズ・コンテキストおよび 64ビット・ポインタ・サイズ・コンテキストの中でそれぞれ宣言されています。

[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ] [ DOC Home ]