ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
Oracle Solaris Studio 12.3: C ユーザーガイド Oracle Solaris Studio 12.3 Information Library (日本語) |
5.2.1 #pragma alias_level level (list)
5.2.1.1 #pragma alias (type, type [, type]...)
5.2.1.2 #pragma alias (pointer, pointer [, pointer] ...)
5.2.1.3 #pragma may_point_to (pointer, variable [, variable] ...)
5.2.1.4 #pragma noalias (type, type [, type]...)
5.2.1.5 #pragma noalias (pointer, pointer [, pointer] ...)
5.2.1.6 #pragma may_not_point_to (pointer, variable [, variable] ...)
5.3.2 構造体ポインタへの void ポインタのキャスト
ここでは、実際のソースファイルに登場する可能性の高いコードの例を説明します。それぞれの例のあとに、コンパイラの仮定について説明します。これらの仮定は、適用レベルの型に基づいた解析によって作成されます。
次のコードを考えてみましょう。さまざまなレベルの別名設定でコンパイルすることにより、それぞれの型の別名設定の関係性を理解できます。
struct foo { int f1; short f2; short f3; int f4; } *fp; struct bar { int b1; int b2; int b3; } *bp; int *ip; short *sp;
この例が -xalias_level=any オプションでコンパイルされる場合、コンパイラは次の間接アクセスを相互の別名とみなします。
*ip、*sp、*fp、*bp、fp->f1、fp->f2、fp->f3、fp->f4、bp->b1、bp->b2、bp->b3
この例が -xalias_level=basic オプションでコンパイルされる場合、コンパイラは次の間接アクセスを相互の別名とみなします。
*ip、*bp、fp->f1、 fp->f4、bp->b1、bp->b2、 bp->b3
また、*sp、fp->f2、および fp->f3 は相互に別名設定でき、*sp および *fp も相互に別名設定できます。
しかし、-xalias_level=basic を指定した場合、コンパイラは次のように仮定します。
*ip は *sp を別名設定しません。
*ip は、fp->f2 および fp->f3 を別名設定しません。
*sp は、fp->f1、fp->f4、bp->b1、bp->b2、および bp->b3 を別名設定しません。
2 つの間接アクセスの基本型が異なるため、コンパイラはこれらの仮定を作成します。
この例が -xalias_level=weak オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
*ip は、*fp、 fp->f1、fp->f4、*bp、bp->b1、bp->b2、および bp->b3 を別名設定できます。
*sp は、*fp、fp->f2、および fp->f3 を別名設定できます。
fp->f1 は、bp->b1 を別名設定できます。
fp->f4 は、bp->b3 を別名設定できます。
コンパイラは、fp->fp1 が bp->b2 を別名設定しないと仮定します。これは、f1 が構造体に 0 のオフセットを保持するフィールドである一方で、b2 が構造体に 4 バイトのオフセットを保持するフィールドであるからです。同様に、コンパイラは、fp->f1 が bp->b3 を別名設定せず、fp->f4 が bp->b1 または bp->b2 を別名設定しないと仮定します。
この例が -xalias_level=layout オプションでコンパイルされる場合、コンパイラは、次の情報を仮定します。
*ip は、*fp、 *bp、fp->f1、fp->f4、bp->b1、bp->b2、および bp->b3 を別名設定できます。
*sp は、*fp、fp->f2、および fp->f3 を別名設定できます。
fp->f1 は、bp->b1 および *bp を別名設定できます。
*fp および *bp は相互に別名設定できます。
fp->f4 は、bp->b3 を別名設定しません。これは、f4 と b3 が foo および bar の共通初期シーケンスで対応するフィールドではないからです。
この例が -xalias_level=strict オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
*ip は、*fp、 fp->f1、fp->f4、*bp、bp->b1、bp->b2、および bp->b3 を別名設定できます。
*sp は、*fp、fp->f2、および fp->f3 を別名設定できます。
-xalias_level=strict を指定すると、コンパイラは、*fp、*bp、fp->f1、fp->f2、fp->f3、fp->f4、bp->b1、bp->b2、および bp->b3 が相互に別名設定しないと仮定します。これは、フィールド名が無視されるときに、foo および bar が同じではないからです。ただし、fp は fp->f1 を別名設定し、bp は bp->b1 を別名設定します。
この例が -xalias_level=std オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
*ip は、*fp、 fp->f1、fp->f4、*bp、bp->b1、bp->b2、および bp->b3 を別名設定できます。
*sp は、*fp、fp->f2、および fp->f3 を別名設定できます。
ただし、fp->f1 は、bp->b1、bp->b2、または bp->b3 を別名設定しません。これは、フィールド名が注視されるときに、foo および bar が同じではないからです。
この例が -xalias_level=strong オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
*ip は、fp->f1、fp->f4、bp->b1、bp->b2、および bp->b3 を別名設定しません。ポインタ (*ip など) が構造体内部をポイントしないはずだからです。
同様に、*sp は、fp->f1 または fp->f3 を別名設定しません。
型が異なるため、*ip は、*fp、*bp、および *sp を別名設定しません。
型が異なるため、*sp は、*fp、*bp、および *ip を別名設定しません。
次の例のソースコードを考えてみましょう。さまざまなレベルの別名設定でコンパイルすることにより、それぞれの型の別名設定の関係性を理解できます。
struct foo { int f1; int f2; int f3; } *fp; struct bar { int b1; int b2; int b3; } *bp;
この例が -xalias_level=any オプションでコンパイルされる場合、コンパイラでは、次の別名情報を仮定します。
*fp、*bp、fp->f1、fp->f2、fp->f3、bp->b1、bp->b2、および bp->b3 はすべて相互に別名設定できます。2 つのメモリーアクセスが -xalias_level=any レベルで相互に別名設定するからです。
この例が -xalias_level=basic オプションでコンパイルされる場合、コンパイラでは、次の別名情報を仮定します。
*fp、*bp、fp->f1、fp->f2、fp->f3、bp->b1、bp->b2、および bp->b3 はすべて相互に別名設定できます。すべての構造体フィールドが同じ基本型であるため、ポインタ *fp および *bp を使用する 2 つのフィールドアクセスは、この例において相互に別名設定できます。
この例が -xalias_level=weak オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
*fp および *fp は相互に別名設定できます。
fp->f1 は、bp->b1、 *bp、および *fp を別名設定できます。
fp->f2 は、bp->b2、 *bp、および *fp を別名設定できます。
fp->f3 は、bp->b3、 *bp、および *fp を別名設定できます。
ただし、-xalias_level=weak を指定すると、次の制限が課されます。
fp->f1 は、bp->b2 または bp->b3 を別名設定しません。f1 のオフセットが 0 である一方で、b2 が 4 バイトのオフセットを保持し、b3 が 8 バイトのオフセットを保持するからです。
fp->f2 は、bp->b1 または bp->b3 を別名設定しません。f2 が 4 バイトのオフセットを保持する一方で、b1 が 0 バイトのオフセットを保持し、b3 が 8 バイトのオフセットを保持するからです。
fp->f3 は、bp->b1 または bp->b2 を別名設定しません。f3 が 8 バイトのオフセットを保持する一方で、b1 のオフセットが 0 バイトであり、b2 が 4 バイトのオフセットを保持するからです。
この例が -xalias_level=layout オプションでコンパイルされる場合、コンパイラでは、次の別名情報を仮定します。
*fp および *bp は相互に別名設定できます。
fp->f1 は、bp->b1、 *bp、および *fp を別名設定できます。
fp->f2 は、bp->b2、 *bp、および *fp を別名設定できます。
fp->f3 は、bp->b3、 *bp、および *fp を別名設定できます。
ただし、-xalias_level=layout を指定すると、次の制限が課されます。
fp->f1 は、bp->b2 または bp->b3 を別名設定しません。foo および bar の共通初期シーケンスにおいて、フィールド f1 がフィールド b1 に対応するからです。
fp->f2 は、bp->b1 または bp->b3 を別名設定しません。foo および bar の共通初期シーケンスにおいて、フィールド f2 がフィールド b2 に対応するからです。
fp->f3 は、bp->b1 または bp->b2 を別名設定しません。foo および bar の共通初期シーケンスにおいて、フィールド f3 がフィールド b3 に対応するからです。
この例が -xalias_level=strict オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
*fp および *bp は相互に別名設定できます。
fp->f1 は、bp->b1、 *bp、および *fp を別名設定できます。
fp->f2 は、bp->b2、 *bp、および *fp を別名設定できます。
fp->f3 は、bp->b3、 *bp、および *fp を別名設定できます。
ただし、-xalias_level=strict を指定すると、次の制限が課されます。
fp->f1 は、bp->b2 または bp->b3 を別名設定しません。foo および bar の共通初期シーケンスにおいて、フィールド f1 がフィールド b1 に対応するからです。
fp->f2 は、bp->b1 または bp->b3 を別名設定しません。foo および bar の共通初期シーケンスにおいて、フィールド f2 がフィールド b2 に対応するからです。
fp->f3 は、bp->b1 または bp->b2 を別名設定しません。foo および bar の共通初期シーケンスにおいて、フィールド f3 がフィールド b3 に対応するからです。
この例が -xalias_level=std オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
fp->f1、fp->f2、fp->f3、 bp->b1、bp->b2、および bp->b3 は相互に別名設定しません。
この例が -xalias_level=strong オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
fp->f1、fp->f2、fp->f3、 bp->b1、bp->b2、および bp->b3 は相互に別名設定しません。
次の例のソースコードは、特定レベルの別名設定が内部ポインタを処理できないことを示します。内部ポインタの定義については、表 B-13 を参照してください。
struct foo { int f1; struct bar *f2; struct bar *f3; int f4; int f5; struct bar fb[10]; } *fp; struct bar struct bar *b2; struct bar *b3; int b4; } *bp; bp=(struct bar*)(&fp->f2);
この例の参照解除は、weak、layout、strict、または std でサポートされません。ポインタ割り当て bp=(struct bar*)(&fp->f2) の実行後、対になった 次のメモリーアクセスは同じメモリー位置に接触します。
fp->f2 および bp->b2 は、同じメモリー位置にアクセスします。
fp->f3 および bp->b3 は、同じメモリー位置にアクセスします。
fp->f4 および bp->b4 は、同じメモリー位置にアクセスします。
ただし、オプション weak、layout、strict、および std を指定する場合、コンパイラは、fp->f2 および bp->b2 が別名設定しないことを仮定します。コンパイラがこのように仮定する理由は、b2 のオフセットが 0 である一方で f2 が 4 バイトのオフセットを保持することと、foo および bar が共通の初期シーケンスを保持しないことにあります。同様に、コンパイラは、bp->b3 が fp->f3 を別名設定しないこと、および bp->b4 が fp->f4 を別名設定しないことも仮定します。
そのため、ポインタ割り当てbp=(struct bar*)(&fp->f2) により、別名情報に関するコンパイラの仮定が正しくない状況が作成されます。この状況は不正な最適化につながる可能性があります。
次の例に示されている変更を行なったあとで、コンパイルを実行してください。
struct foo { int f1; struct bar fb; /* Modified line */ #define f2 fb.b2 /* Modified line */ #define f3 fb.b3 /* Modified line */ #define f4 fb.b4 /* Modified line */ int f5; struct bar fb[10]; } *fp; struct bar struct bar *b2; struct bar *b3; int b4; } *bp; bp=(struct bar*)(&fp->f2);
ポインタ割り当て bp=(struct bar*)(&fp->f2) の実行後、対になった 次のメモリーアクセスは同じメモリー位置に接触します。
fp->f2 および bp->b2
fp->f3 および bp->b3
fp->f4 および bp->b4
このコード例に示された変更内容から、式 fp->f2 は式 fp->fb.b2 の別の形式であることがわかります。fp->fb が型 bar であるため、fp->f2 は bar の b2 フィールドにアクセスします。さらに、bp->b2 も bar の b2 フィールドにアクセスします。そのため、コンパイラは、fp->f2 が bp->b2 を別名設定することを仮定します。同様に、コンパイラは、fp->f3 が bp->b3 を別名設定し、fp->f4 が bp->b4 を別名設定することも仮定します。その結果、コンパイラの仮定する別名設定は、ポインタ割り当てで設定された実際の別名と一致します。
次の例のソースコードを考えてみましょう。
struct foo { int f1; int f2; } *fp; struct bar { int b1; int b2; } *bp; struct cat { int c1; struct foo cf; int c2; int c3; } *cp; struct dog { int d1; int d2; struct bar db; int d3; } *dp;
この例が -xalias_level=weak オプションでコンパイルされる場合、コンパイラは、次の別名情報を仮定します。
fp->f1 は、bp->b1、cp->c1、dp->d1、cp->cf.f1、および df->db.b1 を別名設定できます。
fp->f2 は、bp->b2、cp->cf.f1、dp->d2、cp->cf.f2、 df->db.b2、および cp->c2 を別名設定できます。
bp->b1 は、fp->f1、cp->c1、dp->d1、cp->cf.f1、および df->db.b1 を別名設定できます。
bp->b2 は、fp->f2、cp->cf.f1、dp->d2、cp->cf.f1、および df->db.b2 を別名設定できます。
fp->f2 は、cp->c2 を別名設定できます。*dp が *cp を別名設定でき、*fp がdp->db を別名設定できるからです。
cp->c1 は、fp->f1、bp->b1、dp->d1、および dp->db.b1 を別名設定できます。
cp->cf.f1 は、fp->f1、fp->f2、bp->b1、bp->b2、 dp->d2、および dp->d1 を別名設定できます。
cp->cf.f1 は、dp->db.b1 を別名設定しません。
cp->cf.f2 は fp->f2、bp->b2、dp->db.b1、および dp->d2 を別名設定できます。
cp->c2 は、dp->db.b2 を別名設定できます。
cp->c2 は dp->db.b1 を別名設定せず、 cp->c2 は dp->d3 を別名設定しません。
オフセットに関連して、*dp が cp->cf を別名設定する場合にかぎり、cp->c2 は db->db.b1 を別名設定できます。ただし、*dp が cp->cf を別名設定する場合、dp->db.b1 は foo cf の末尾を超えて別名設定する必要がありますが、これはオブジェクトの制限事項で禁じられています。そのため、コンパイラは、cp->c2 が db->db.b1 を別名設定できないと仮定します。
cp->c3 は、dp->d3 を別名設定できます。
cp->c3 は、dp->db.b2 を別名設定しません。参照解除に関連する型のフィールドのオフセットが異なり、重複することがないため、これらのメモリー参照は別名設定を行いません。この事実に基づき、コンパイラは、それらのメモリー参照が別名設定できないと仮定します。
dp->d1 は、fp->f1、bp->b1、および cp->c1 を別名設定できます。
dp->d2 は、fp->f2、bp->b2、および cp->cf.f1 を別名設定できます。
dp->db.b1 は、fp->f1、bp->b1、および cp->c1 を別名設定できます。
dp->db.b2 は、fp->f2、bp->b2、cp->c2、および cp->cf.f1 を別名設定できます。
dp->d3 は、cp->c3 を別名設定できます。
dp->d3 は、cp->cf.f2 を別名設定しません。参照解除に関連する型のフィールドのオフセットが異なり、重複することがないため、これらのメモリー参照は別名設定を行いません。この解析に基づき、コンパイラは、それらが別名設定できないと仮定します。
この例が -xalias_level=layout オプションでコンパイルされる場合、コンパイラでは、次の別名情報だけを想定します。
fp->f1、bp->b1、cp->c1、および dp->d1 はすべて相互に別名設定できます。
fp->f2、bp->b2、および dp->d2 はすべて相互に別名設定できます。
fp->f1 は、cp->cf.f1 および dp->db.b1 を別名設定できます。
bp->b1 は、cp->cf.f1 および dp->db.b1 を別名設定できます。
fp->f2 は、cp->cf.f2 および dp->db.b2 を別名設定できます。
bp->b2 は、cp->cf.f2 および dp->db.b2 を別名設定できます。
この例が -xalias_level=strict オプションでコンパイルされる場合、コンパイラでは、次の別名情報だけを想定します。
fp->f1 および bp->b1 は相互に別名設定できます。
fp->f2 および bp->b2 は相互に別名設定できます。
fp->f1 は、cp->cf.f1 および dp->db.b1 を別名設定できます。
bp->b1 は、cp->cf.f1 および dp->db.b1 を別名設定できます。
fp->f2 は、cp->cf.f2 および dp->db.b2 を別名設定できます。
bp->b2 は、cp->cf.f2 および dp->db.b2 を別名設定できます。
この例が -xalias_level=std オプションでコンパイルされる場合、コンパイラでは、次の別名情報だけを想定します。
fp->f1 は、cp->cf.f1 を別名設定できます。
bp->b1 は、dp->db.b1 を別名設定できます。
fp->f2 は、cp->cf.f2 を別名設定できます。
bp->b2 は、dp->db.b2 を別名設定できます。
次の例のソースコードを考えてみましょう。
struct foo { short f1; short f2; int f3; } *fp; struct bar { int b1; int b2; } *bp; union moo { struct foo u_f; struct bar u_b; } u;
さまざまな別名レベルに基づくコンパイラの仮定を、次に示します。
この例が -xalias_level=weak オプションでコンパイルされる場合、fp->f3 および bp->b2 は相互に別名設定できます。
この例が -xalias_level=layout オプションでコンパイルされる場合、フィールドは相互に別名設定できません。
この例が -xalias_level=strict オプションでコンパイルされる場合、fp->f3 および bp->b2 は相互に別名設定できます。
この例が -xalias_level=std オプションでコンパイルされる場合、フィールドは相互に別名設定できません。
次の例のソースコードを考えてみましょう。
struct bar; struct foo { struct foo *ffp; struct bar *fbp; } *fp; struct bar { struct bar *bbp; long b2; } *bp;
さまざまな別名レベルに基づくコンパイラの仮定を、次に示します。
この例が -xalias_level=weak オプションでコンパイルされる場合、fp->ffp および bp->bbp だけが相互に別名設定できます。
この例が -xalias_level=layout オプションでコンパイルされる場合、fp->ffp および bp->bbp だけが相互に別名設定できます。
この例が -xalias_level=strict オプションでコンパイルされる場合、フィールドは別名設定できません。タグが削除されたあとも、2 つの構造体の型が異なるからです。
この例が -xalias_level=std オプションでコンパイルされる場合、フィールドは別名設定できません。2 つの型とタグが同じではないからです。
次の例のソースコードを考えてみましょう。
struct foo; struct bar; #pragma alias (struct foo, struct bar) struct foo { int f1; int f2; } *fp; struct bar { short b1; short b2; int b3; } *bp;
この例のプラグマにより、foo および bar が相互に別名設定できることがコンパイラに伝えられます。コンパイラは、別名情報について次のように仮定します。