2

uint32_t を使用して任意のタイプのアイテムを移動し、それらを読み戻すことは、厳密なエイリアシング規則に違反しますか? もしそうなら、uint32_ts の配列から任意の型の配列への memcpy への厳密なエイリアシング規則にも違反し、要素を読み戻しますか?

次のコード サンプルは、両方のケースを示しています。

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

int main(void) {
    const char *strings[5] = {
        "zero", "one", "two", "three", "four"
    };
    uint32_t buffer[5];
    int i;

    assert(sizeof(const char*) == sizeof(uint32_t));

    memcpy(buffer, strings, sizeof(buffer));

    //twiddle with the buffer a bit
    buffer[0] = buffer[3];
    buffer[2] = buffer[4];
    buffer[3] = buffer[1];

    //Does this violate strict aliasing?
    const char **buffer_cc = (const char**)buffer;
    printf("Test 1:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", buffer_cc[i]);
    printf("\n");

    //How about this?
    memcpy(strings, buffer, sizeof(strings));
    printf("Test 2:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", strings[i]);
    printf("\n");

    return 0;
}

32 ビット プラットフォームに関する私の仮定は無視してください。また、要素が uint32_t と同じサイズでない場合は、それらをパディングして正しい数の uint32_t をコピーすることを知っています。私の質問は、そうすることが厳密なエイリアシングに違反するかどうかに焦点を当てています。

4

2 に答える 2

4

最初のループuint32_t技術的に厳密なエイリアシングに違反しています - type の左辺値を介してオブジェクトにアクセスしますchar *。ただし、この特定のケースでオプティマイザがどのように問題を引き起こすかを理解するのは困難です。少し変更した場合、次のようなことをしていました。

printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);

同じ文字列が 2 回表示されることがあります。これは、2 行目で type のオブジェクトのみを変更しているため、オプティマイザーがレジスターに 1 回だけロードする権限を持っているためbuffer_cc[0]ですuint32_t

戻ってくる2 番目のループmemcpyは問題ありません。

于 2009-12-18T05:13:30.240 に答える
1

buffer_cc[0]およびstrings[3](たとえば) 同じメモリ位置を参照するが同じ型のポインターであるため、厳密なエイリアシングに違反しません。buffer[0]はポインターではないため、厳密なエイリアシングに違反しません。ポインターを逆参照するときにエイリアシングの最適化が発生するため、これが問題を引き起こすとは思いません。

コードと質問の最後の段落で言及したように、サンプル コードの実際の問題は、ポインターと uint32_t のサイズが異なる場合に発生します。

また、char*厳密なエイリアシングに違反することなく、いつでも a を別の型にエイリアスすることができますが、その逆はできません。

于 2009-12-18T05:00:48.567 に答える