高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QA1112
QTML, c2pstr and Pascal strings


Q:ある QuickTime のコードを Macintosh から Windows に移植しようとしています。Windows では Visual C++ を使っています。Pascal 文字列の作成時に、厄介な問題に遭遇しています。c2pstr を呼び出すたびにアクセス違反になるのですが、同じコードが CodeWarrior では問題なく機能しています。何が間違っているのでしょう。

A:アクセス違反の原因として一番考えられるのは、文字列データが読み取り専用メモリにあることです。

C 言語文字列は、文字列の最初の文字で始まり、ヌルの値(ASCII コードでの値はゼロ)で終わります。 Pascal 文字列は、文字列の長さ(バイト数)で始まり、終了文字はありません。

Macintosh では、型が異なります。

C 言語文字列は char *

Pascal 文字列は 符号なしの char *

c2pstr を呼び出すと、文字列はその場で上書きされ、C から Pascal に変換されます。これは、すべての文字をずらして、終了のヌル文字を削除し、先頭に長さ(バイト数)を挿入することによって行われます。

たとえば、"hello\0x00" は、"\0x05hello" になります。

どのプラットフォームにおいても、C 言語のリテラル文字列を c2pstr に渡すべきではありません。これには 2 つの理由があります。最初の理由は、文字列データが読み取り専用メモリにある可能性があり、その場合には変更するとアクセス違反が生じるからです。2 番目の理由は、最初の呼び出しが成功したとしても、以降の呼び出しによって文字がさらに移動されることで、無意味なデータが生まれ、メモリ内容が不正になるからです。

"\0x05hello" は、"\0x06\0x05hello" になります(文字列バッファの後ろのバイトがヌル文字と仮定した場合)。

Macintosh の C コンパイラは、"\phello" などの Pascal 文字列を作成できる "\p" という表記をサポートしています。 Win32 コンパイラは通常、この表記をサポートしていないので "phello" と同じ文字列を生成します。

コードの移植性を確保するために、QuickTime Media Layer(QTML)は、長さバイトが 112 (112 = 0x70 = 'p') に設定されている Pascal 文字列を頻繁に調べて、これらの文字列が実際には、間違って生成された C 文字列でないかどうかを確かめます。これらの文字列が間違って生成された C 文字列の場合は、c2pstr を呼び出して、それらをその場で Pascal 文字列に変換します。しかし、QTML は、これを一度しか行わないので、上述したような無意味なデータを生成し始めることはありません。

この QTML 機能を利用する開発者は、このような Pascal 文字列を書き込み可能なメモリに入れるように注意しなければなりません。自分の開発システムをこれを行うように設定することもできます。

または、この文字列を、非定数文字列バッファの初期値にもできます。

static char helloStr[] = "\phello";

なお、開発者が C 文字列と Pascal 文字列の変換に利用できる推奨の関数があります。

    CopyPascalStringToC
    CopyCStringToPascal
    c2pstrcpy
    p2cstrcpy


これらの関数は、その場での変換(つまり、src と dst のパラメータが同じメモリアドレスを指させる)が可能なように作られていますが、前述したように、読み取り専用のバッファの内容を間違って変更しようとしたり、定数を不用意に破棄したりする原因になり得る、その場での変換しか行わないことによる制約はありません。


[2002 年 1 月 21 日]