2016-03-25 4 views
3

厳密なエイリアシング(特に "What is the strict aliasing rule?"と "Strict aliasing rule and 'char *' pointers")については多くの議論がありますが、これは明示的に対処されていないコーナーケースです。C++ 11での厳密なエイリアシングでは、char *に_write_、エイリアスの非文字*から_read_に定義されていますか?

は、このコードを考えてみましょう:

int x; 
char *x_alias = reinterpret_cast<char *>(&x); 
x = 1; 
*x_alias = 2; // [alias-write] 
printf("x is now %d\n", x); 

は、印刷された値は、[別名 - 書き込み]の変更を反映する必要がありますか? (明らかにエンディアンと表現考慮事項がありますが、それはここに私の心配はありません。)

C++ 11の仕様は、この言語(強調鉱山)を使用しての有名な[basic.lval]句:

は、If

  • ...

    • ...様々な他の条件:プログラムは、動作が定義されていない次のいずれかのタイプ以外のglvalueを通してアクセスオブジェクトの格納された値に試みまたはunsigned charタイプ。
  • Iは(のnonchar物体上に文字を書く)「アクセス」のみ(のnoncharオブジェクトから文字を読み取る)読み出し動作したり、また書込み動作を指すかどうかを把握することはできません。スペックに「アクセス」という正式な定義がある場合、私はそれを見つけることができませんが、他の場所では、スペックは読み取りのための「アクセス」と書き込みのための「更新」を使用するようです。

    これは、デシリアライズ時に特に重要です。 charバッファからオブジェクトへの中間のmemcpy()を必要とせずに、データをワイヤからオブジェクトに直接渡すことは便利で効率的です。

    答えて

    2

    は、それが、その後_、CHAR *に_書き込み_に定義された*エイリアスのnoncharから_を読んでいるのですか?

    はい。

    [alias-write]の変更が印刷された値に反映されている必要がありますか?

    はい。

    厳密なエイリアシングは((unsignedchar*は何でもエイリアスできることを示します。 「アクセス」という言葉は、読取り操作と書込み操作の両方を意味します。

    +0

    ありがとうございます!この解釈をバックアップする参考資料はありますか? (例えば、スペックは私が見逃したどこかの "アクセス"を定義していますか?多くの場所で、 "読む"だけを意味するためにその単語を使用しているようです。) –

    +1

    Aha、見つけました。 "3.1アクセス<実行時のアクション>オブジェクトの値を変更または変更することができます。 –

    +0

    もちろん、両方のポインタで参照されるアドレスに本当に 'AliasedType'が宣言されている場合にのみ定義されます。すなわち、あなたは 'AliasedType'を宣言し、それにバイトを読み込み、それを読むことができます。しかし、 'unsigned char'の配列を宣言することはできませんし、バイトを読み込み、前に存在しなかったときにそのアドレスから' AliasedType'をマジックアップします。 –

    0

    C89規格の作成者は、でサポートされており、非サポートの場合は2つの方法があります

    /* global definitions */ 
    int thing; 
    double *p; 
    
    int x(double *p) 
    { 
        thing = 1; 
        *p = 1.0; 
        return thing; 
    } 
    

    :コンパイラは次のようにすべての可能なエイリアシングが与えられた何か を処理することを必要としない

    int thing; 
    unsigned char *p = &x; 
    int i; 
    for (i=0; i<sizeof thing; i++) 
        p[i] = getbyte(); 
    

    int thing = somevalue(); 
    unsigned char *p = &x; 
    int i; 
    for (i=0; i<sizeof thing; i++) 
        putbyte(p[i]); 
    

    が、 (1)サポートされるケースでは、他のタイプではなく文字型ポインタを使用してアクセスされ、(2)クエストのものの住所の後にonが別の型に変換されると、そのポインタを使用するストレージへのすべてのアクセスは、元の左辺値を使用して次のアクセスの前に行われます。スタンダードの著者は、残念なことに第1のものだけを重要と見なしましたが、第2の方法はエイリアシングが重要となるケースを識別する信頼性の高い方法でした。スタンダードが第2に集中していた場合、コンパイラがあなたの例でエイリアシングを認識する必要はないかもしれません。しかし、標準では、実際の文字データを処理しているコードのパフォーマンスに不必要な影響を与えたにもかかわらず、コンパイラがプログラムが文字タイプを使用するときには、エイリアシングを認識する必要があります。

    この基本的な間違いを修正するのではなく、CとC++の両方の他の標準が同じ壊れたアプローチで単純に継続しています。

    関連する問題