10

このようなオブジェクトがある場合:

struct {
    uint32_t n;
    uint8_t c;
} blob {};

次に、3 つの「パディングされた」バイトがあります。

パディングされたバイトにアクセスするのはUBですか?例えば:

uint8_t * data = reinterpret_cast<uint8_t*>(&blob);
std::cout << data[4] << data[5] << data[6] << data[7];

最初はこれがおそらく UB だと思っていましたが、それが本当なら memcpy も UB になるでしょう:

memcpy(buf, &blob, sizeof(blob));

私の具体的な質問は次のとおりです。

  • パディングされたバイトにアクセスするのはUBですか?
  • いいえの場合、それは値も定義されていることを意味しますか?
4

5 に答える 5

6

いいえ、オブジェクト全体がゼロで初期化されている場合(標準では、オブジェクトがゼロで初期化されている場合、パディングは0ビットに初期化されると標準で規定されています)または値で初期化されている場合、パディングにアクセスするのはUBではありません。ユーザー定義のコンストラクターを持つクラス。

于 2013-02-06T20:52:48.273 に答える
0

適切な状況下では、これで UB になる可能性があると思います。私が考えているのは、ECCまたはパリティチェックのいずれかを備えたメモリがあり、メモリへの書き込みによってecc /パリティビットが設定される場所です。メモリのブロックが以前に使用されたことがなく [AT ALL に書き込まれたことがない] 場合、パディング フィールドの初期化されていないバイトを読み取ると、一度も書き込まれたことのないメモリが読まれています。

もちろん、そのようなシステムでは、起動中のある時点で「すべてのメモリを埋める」ことを行うだけで、大きな問題を回避できます。

struct Blob 
{
    uint32_t n;
    uint8_t c;
};

Blob *b = malloc(sizeof(Blob)*10);

for(int i = 0; i < 10; i++)
{
   b[i].n = i;
   b[i].c = i;
 }


 ...

 Blob a[3];

 memcpy(a, &b[1], sizeof(a));    // Copies 3 * Blob objects, including padding. 

現在、b[x] のすべてのビットが設定されているわけではないため、パリティ/ecc エラーが原因で、memcpy 内のデータのコピーに失敗する可能性があります。それはかなり悪いでしょう。しかし同時に、コンパイラにすべてのパディング領域を強制的に「設定」させることはできません。

結論から言うとこれはUBですが、特別な事情がない限り問題になることはまずありません。memcpy確かに、多くのコードで上記のタイプのコードを目にするでしょう。

于 2013-02-06T21:07:32.403 に答える
0

POD 構造体は、少なくとも sizeof(struct) バイト (パディング バイトを含む) の連続したメモリ ブロックに存在します。パディング バイト (存在する場合) へのアクセスは、最初に初期化されていない場合にのみ UB になります。

memset(&s, 0, sizeof(s));

これにより、パディングを含むすべてのバイトが初期化されます。その後、パディングからの読み取りは UB になりません。

もちろん、memset()これは C イズムであり、C++ では絶対にやらないことですよね?

于 2013-02-06T22:05:21.190 に答える
0

未定義の動作でない場合、それは確かに実装定義です。C++ 標準はプログラムの動作についてあまり保証しませんが、システムの ABI 仕様 ( Linux を使用している場合はSysV ) は保証します。パディング ビットをいじっている場合は、任意の C++ 準拠システムでプログラムがどのように動作するかよりも、システムでプログラムがどのように動作するかに関心があるのではないかと思います。

于 2013-02-06T21:44:31.333 に答える
0

Cでは、未定義の動作ではありません。初期化されていないもの (オブジェクトのパディングなど) にアクセスすることで未定義の動作が発生するのは、オブジェクトに自動ストレージ期間があり、そのアドレスが取得されていない場合のみです。

6.3.2.1.2: 左辺値が、register ストレージ クラスで宣言できた可能性のある自動ストレージ期間のオブジェクトを指定し (そのアドレスが取得されたことがない)、そのオブジェクトが初期化されていない (初期化子で宣言されておらず、割り当てもされていない) 場合使用前に実行されている場合)、動作は未定義です。

ただし、この場合、( を使用して&) アドレスを取得しているため、動作は明確に定義されています (エラーは発生しません) が、ランダムな値が得られる可能性があります。

C++ では、通常そうであるように、すべての賭けは無効です。

于 2013-02-06T21:31:00.020 に答える