2017-07-06 1 views
3

私が知っている、私はすでにそれを見たが、なぜこの未定義の動作がある私は、任意の良い説明を見つけることができませんでした:この厳密なエイリアシングはどのようにして未定義の動作ですか?

#include <stdio.h> 
#include <stdint.h> 

//Common union for both types 
union float_int { 
    float f; 
    uint32_t i; 
}; 

int main(void) { 
    union float_int fi; 
    //This should be problematic 
    uint32_t* i_ptr = (uint32_t *)&fi.f; 

    fi.f = 10.0f; 
    printf("%f : %u\r\n", fi.f, fi.i); //Prints: 10.000000 : 1092616192 which is OK 
    printf("%u\r\n", *i_ptr); //Prints: 1092616192 which is also OK 

    return 0; 
} 

我々はメモリ表現をチェックすると、両方が4-bytes長いですので、何のメモリオーバーフローがではありませんポインティングまたは同様のもの。

この定義されていない動作はどうですか?

int main() { 
    union float_int fi; 
    void* v_ptr = &fi.f; 
    uint32_t* i_ptr = (uint32_t *)v_ptr; 
} 

このコードはまだ定義されていませんか?私はfloatの番号をunsigned integer 32-bitsとしています。

memcpyを使用するのはなぜですか?

+0

'indefined' - >' undefined'? –

+0

@SouravGhoshはい、ありがとうございます。 – tilz0R

+0

@Stargateurは私に正解をお願いします。私はそれを見つけることができませんでした。 – tilz0R

答えて

1

これは厳密なエイリアシングではなく、違反です。厳密なエイリアシングのです。

まず、あなたがして

uint32_t* i_ptr = (uint32_t *)&fi.f; //converting to a non-character type pointer 

をやっている、あなたが問題を引き起こし

printf("%u\r\n", *i_ptr); //access value via incompatible lvalue expr. 

することにより、そのアクセスしてみてください。 floatおよびuint32_tは、ではなく、互換タイプです。オブジェクトのみ 次のタイプの1つを有する左辺値表現によってアクセスその格納された値でなければならないC11、章§6.5/ P7

を引用

88)

は -

- オブジェクトの有効な型と互換性のある型の修飾バージョン

- オブジェクトの有効な種類に対応する符号付きまたは符号なしのタイプであるタイプ、

- オブジェクトの 効果的なタイプの修飾バージョンに対応する符号付きまたは符号なしのタイプであるタイプ文字種 - 、

- その (subaggregate又は含ま組合のメンバー、再帰的に含む)のメンバー、または

うち、前述のタイプのいずれかを含む凝集体または共用タイプ。コメントへの返信で


、のはC11、章の§6.2.6を見てみましょう。他のオブジェクト・タイプの非ビット・フィールド・オブジェクトに格納された1つの

値はnはバイト単位で、その型のオブジェクトの大きさであるn × CHAR_BIT ビットから成ります。値はのオブジェクト(例えば、memcpyによって) にコピーされてもよい。結果のバイトセットは、値のオブジェクト表現と呼ばれる です。

あるオブジェクト表現は、オブジェクト・タイプの値を表す必要はありません。格納されたオブジェクトの 値がそのような表現を持ち、 に文字型を持たない左辺式によって読み取られた場合の動作は未定義です。 [...]そのような表現は、トラップ表現の と呼ばれます。

+0

私はそれらがそうではないことに同意しますが、どちらも4バイト長であり、両方とも同じメモリを指しています。 CPUは何があっても気にせず、読んで解釈するだけです。私にとっては奇妙です。そして、 'memcpy'だけがこれを解決できます。さらに奇妙な。とにかくありがとう。 – tilz0R

+1

@ tilz0Rよろしくお願いします。 –

+0

私は1つの答えでバッファのキャスティングを見つけることを望む。同様の状況。更新をありがとう。 – tilz0R

0

浮動小数点表現と整数表現はお互いに異なります。 このように、このような共用体を定義することは、良いユースケースではありません。

例では、void *からuint32_t *へのキャストを実行します。 キャストはポインタレベルで行われます。 これは、i_ptrが、ビット自体を変更することなく、インタージャーとして見えるメモリ内の場所を指し示すことを意味します。

要約すると、このキャストを機能させたい場合は、変数の内部表現を変更する必要があります。例:

printf("%u\r\n", (uint32_t)*i_ptr); 
+0

"unionを定義する、そうすることはできません":これは意味をなさない。組合は全くできないと私は思います! –

+0

@YvesDaoustが同意する、私はそれをより正確に言い換える – drorco

関連する問題