DEC Cランタイム・ライブラリは, 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
形式を呼び出す必要があります。
メモリを割り当てる関数は次に示します。
malloc
calloc
realloc
strdup
_malloc32
, _malloc64
_calloc32
, _calloc64
_realloc32
, _realloc64
_strdup32
, _strdup64
malloc
呼び出しの省略時の設定は_malloc32
になります。
/POINTER_SIZE=64が指定されると,すべてのmalloc
呼び出しの省略時の設定は_malloc64
になります。
アプリケーションが32ビットまたは
64ビットのどちらのメモリ割り当てルーチンを呼び出した場合も,
free
関数があります。
この関数はどちらのサイズのポインタも受け取ります。
メモリ割り当て関数は,64ビット・メモリへのポインタを返す唯一の関数です。 (FILE,WINDOW,DIRなどのように)呼び出しアプリケーションに返されるすべての DEC C RTL構造ポインタは,通常は32ビット・ポインタです。このため32ビットと 64ビットの両方の呼び出し側とも, アプリケーションの中でこれらの構造ポインタを渡すことができます。
32ビット・ポインタまたは64ビット・ポインタのいずれか 1つを引数として受け取る関数に対して, 32ビット・ポインタをその引数として渡すことができます。
しかし,32ビット・ポインタを受け取る関数への引数として, 64ビット・ポインタを渡すことはできません。この操作を試みると, コンパイラによって診断が行われ,MAYLOSEDATAメッセージが表示されます。なお, IMPLICITFUNC診断メッセージが表示された場合,これは,その関数の呼び出しについて, ポインタ・サイズのチェックをこれ以上実行できないことを表します。
特に有効なポインタ・サイズについてのコンパイラの診断メッセージを次に示します。
指定された関数の使用に先立ち,関数プロトタイプが見つからないことを表します。 コンパイラおよびランタイム・システムは,プロトタイプ定義に基づいて, 不適切なポインタ・サイズの使用を検出します。 正しいヘッダ・ファイルがインクルードできないと,不適切な結果が生じたり, ポインタの切り捨てが発生する可能性があります。
この操作を実行するには切り捨てが必要であることを表します。この操作では, 指定されたコンテキストの中で64ビット・ポインタをサポートしない関数に対して, 64ビット・ポインタを渡している可能性があります。または関数の戻り値は 64ビット・ポインタを返し,ソースはその戻り値を 32ビット・ポインタに保存しようとしている可能性があります。
(有効な場合)このメッセージは,キャスト操作により表示が抑止されている本当の MAYLOSEDATAメッセージを出力することを可能にします。
DEC C RTL関数は,次の4種類に分類できます。
3番目の関数は, 単一ポインタ・モードで使用している場合はソース・コードを変更する必要はありません。 ただし混合ポインタ・モードで使用している場合は,ソース・コードの変更が必要です。
4番目の関数は,64ビット・ポインタを使用している場合は十分な注意が必要です。
この種類の関数のうち,プロトタイプにポインタを含まない関数は,
ポインタ・サイズの選択による影響はありません。たとえば
strerror
関数のプロトタイプは次のとおりです。
char * strerror (int error_number);この関数は文字列へのポインタを返しますが,この文字列は DEC C RTLで割り当てられます。その結果,32ビット・アプリケーションと 64ビット・アプリケーションを両方ともサポートするために,この種類のポインタは, 32ビット・ポインタに対応することが常に保証されています。
DEC C RTL内の関数の多くは拡張され,
64ビット・アドレス全体を受け取るようになりました。関数strlen
を例に考えます。
size_t strlen (const char *string);この関数内の唯一のポインタは文字列ポインタです。ユーザが 32ビット・ポインタを渡すと,関数は符号拡張された64ビット・アドレスで動作します。 ユーザが64ビット・アドレスを渡すと,関数はそのアドレスで直接動作します。
DEC C RTLは引き続き,この種類の関数に対して, 1つのエントリ・ポイントだけを持ちます。この種類の関数の 4つのポインタ・サイズ・オプションのいずれを追加する場合も, ソース・コードの変更は必要ありません。OpenVMSマニュアルでは, これらの関数を64ビット・フレンドリと呼びます。
<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修飾子を指定してコンパイルしている場合, 修正されていない関数名を呼び出すと, その修飾子で指定されるポインタ・サイズに対応するインタフェースが呼び出されます。
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 |
32ビット・ポインタしか使用できない関数を 表 11-2に示します。 DEC C RTLは,これらの関数に対して64ビット・サポートを提供していません。
atexit | getopt |
modf | setstate |
execve | iconv |
recvmsg | setvbuf |
execvp | initstate |
sendmsg | |
frexp | ioctl |
setbuf |
関数呼び出し処理の一部として, ユーザが提供する関数へのコールバックを行う関数の一覧を 表 11-3に示します。 コールバック・プロシージャに64ビット・ポインタが渡されることはありません。
from_vms | to_vms |
ftw | tputs |
: #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】を行う必要があります。
: #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ビット・コンテキストで行われます。
: #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
を使用します。
: #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ビット・ポインタ・サイズ・コンテキストの中でそれぞれ宣言されています。