58

開発者が構造体自体ではなく、構造体の最初の要素のアドレスをコピー/比較/設定するときに一貫して使用する、さらに別のコードベースを見つけました。簡単な例を次に示します。

まず、構造体型があります。

typedef struct {
    int a;
    int b;
} foo_t;

次に、そのような構造体のコピーを作成する関数があります。

void bar(foo_t *inp)
{
    foo_t l;
    ...
    memcpy(&l.a, &inp->a, sizeof(foo_t));
    ...
}

私自身memcpyはそのような方法で への呼び出しを記述しませんでした。元の開発者が C のポインターと構造体を完全に把握していなかったのではないかと疑うことから始めました。一般的な開発者なので、自分自身を疑い始めています。

なぜこのスタイルを使用したいのでしょうか?

4

6 に答える 6

62

その代わりに:

memcpy(&l.a, &inp->a, sizeof(foo_t));

出来るよ:

memcpy(&l, inp, sizeof(foo_t));

危険で誤解を招く可能性がありますが、C は最初の構造体メンバーの前にパディングがないことを保証しているため、両方のステートメントは実際にはここで同じことを行います。

ただし、単純な代入演算子を使用して構造体オブジェクトをコピーするのが最善です。

l = *inp;

なぜこのスタイルを使用したいのでしょうか?

私の推測: 無知または悪い規律.

于 2013-11-04T20:47:48.640 に答える
12

memberが最初のメンバーではなくなったmemcpy場合、構造体のメンバーを再配置すると、構造体の境界を超えてアクセスする可能性があるため、このコードは安全ではありません。a

ただし、メンバーが構造体内で意図的に順序付けられており、プログラマーがメンバーから始まりa、構造体の最後まで実行されている、それらのサブセットのみをコピーしたいということが考えられます。その場合は、次の変更でコードを安全にすることができます。

    memcpy(&l.a, &inp->a, sizeof(foo_t) - offsetof(foo_t, a));

これで、構造体メンバーを任意の順序に再配置でき、これmemcpyが範囲外になることはありません。

于 2013-11-05T10:19:26.913 に答える
2

実際、これには正当な使用例が 1 つあります。それは、クラス階層の構築です。

構造体をクラス インスタンスとして扱う場合、通常、最初のメンバー (つまり、オフセット 0) はスーパータイプ インスタンスになります... スーパータイプが存在する場合。これにより、単純なキャストでサブタイプとスーパータイプの間を移動できます。非常に便利。

Darren Stone の意図に関するメモでは、これはC 言語で OO を実行するときに予想されます。

それ以外の場合は、既に挙げた理由から、このパターンを避け、代わりにメンバーに直接アクセスすることをお勧めします。

于 2015-05-28T19:22:26.227 に答える
1

それは本当に悪い習慣です。たとえば、構造体の先頭に別のメンバーが追加されている場合があります。これは非常に不注意な習慣であり、誰もがこれを行うことを読んで驚いています.

他の人はすでにこれらに注目しています。私を悩ませているのはこれです:

struct Foo rgFoo [3];
struct Foo *pfoo = &rgFoo [0];

それ以外の

struct Foo *pfoo = rgfoo;

インデックスで配列を逆参照してから、アドレスを再度取得するのはなぜですか? それはすでにアドレスです。注意すべき唯一の違いは、 pfoo が技術的に

struct Foo *const, 

いいえ

struct Foo *.  

それでも、私は最初のものをいつも見ていました。

于 2013-11-06T16:15:10.480 に答える