0

構造体の 2 つのエントリを交換しようとしています。

これは構造体です:

struct hdr {
    uint8_t ether_dhost[6];
    uint8_t ether_shost[6]; 
}

これらの値を一時配列に保存しようとすると、次の行に次のエラーが表示されます。

uint8_t original_dhost[6];
original_dhost = ethernet_hdr->ether_dhost;

'uint8_t[6]'タイプ 'uint8_t *' からタイプに代入するときの互換性のないタイプ

代わりに、配列ではなくポインターを使用してみます。

uint8_t *original_dhost;

その後、エラーは発生しませんが、に割り当てようとすると、次のethernet_hdr->ether_dhostエラーが発生します。

ethernet_hdr->ether_shost = original_dhost;
incompatible types when assigning to type ‘uint8_t[6]’ from type ‘uint8_t *’

上記の最初のエラーを回避するにはどうすればよいですか? 'uint8_t *'具体的には、フィールドを配列として宣言すると、なぜコンパイラはフィールドが であると言うのですか?

4

6 に答える 6

4

ether_dhost配列です。単純な割り当てステートメントを使用してコピーすることはできません。

ethernet_hdr->ether_dhost最初の要素 (ポインター) のアドレスに解決されるため、最初のエラーが発生しますがuint8_t、その値を新しい配列に割り当てることはできません。

すべての要素をコピーするには、memcpy (またはループ) を使用する必要があります。

uint8_t original_dhost[6];
memcpy(original_dhost,ethernet_hdr->ether_dhost,sizeof(original_dhost));
于 2013-10-03T16:10:06.563 に答える
3

ここにはいくつかの問題があります。

まず、配列式は代入の対象にならないことがあります。のようなものを書くことはできません

uint8_t original_dhost[6];
original_dhost = ethernet_hdr->ether_dhost;

original_dhostは変更可能な左辺値ではないためです。これには理由がありますが、それは以下で明らかになります。ある配列の内容を別の配列にコピーするには、各要素を個別にコピーするか、memcpyライブラリ関数を使用する必要があります。

memcpy( original_dhost, ethernet_hdr->ether_dhost, sizeof original_dhost );

sizeofまたは 単項演算子のオペランドである場合、または宣言で配列を初期化するために使用される文字列リテラルである場合を除き、&「N 要素配列」型の式は、次の式Tに変換 (「減衰」) されます。 「ポインタT」と入力すると、式の値が配列の最初の要素のアドレスになります。結果は変更可能な左辺値ではありません。つまり、割り当てのターゲットにすることはできません。

声明では

original_dhost = ethernet_hdr->ether_dhost;

式のethernet_hdr->ether_dhost型は「6 要素配列uint8_t」です。sizeof単項演算子または単項演算子のオペランドではないため、&「へのポインタ」型の式uint8_t、またはに変換されますuint8_t *。このタイプは と互換性がないuint8_t [6]ため、最初のエラーです。2 番目のエラーは同じ問題です。関係するプレーヤーを逆にしただけです。

それでは、代入の左辺も単純にポインターに変換して、代入を成功させてみませんか? 短い歴史の授業の時間です。

C は、「型のない」言語である B と呼ばれる初期の言語から派生したものです。データが整数、実数値、テキストなどを表すために使用されているかどうかに関係なく、すべてのデータは固定サイズのワードまたは「セル」に格納されていました。メモリは、セルの線形配列として扱われました。次のように、B で配列を宣言したとき

auto arr[N];

コンパイラは N+1 個のセルを確保します。配列の N 個のセルと、配列の最初の要素へのオフセットを格納する追加のセル。次のarrように、シンボルにバインドされます。


            +---+
  arr:      |   | ---+
            +---+    |
             ...     |
            +---+    |
  arr[0]:   |   | <--+
            +---+
  arr[1]:   |   |
            +---+
  arr[2]:   |   |
            +---+
             ...
            +---+
  arr[N-1]: |   |
            +---+

C と同様に、 のような添字操作arr[i]は として計算され*(arr + i)ます。iに格納されているオフセット値に値を追加しarr、結果を逆参照しました。

Dennis Ritchie は、C を開発していた当初は B の配列セマンティクスを保持していましたがstruct、言語に型を追加し始めたときに問題に遭遇しました。彼は、構造体の内容をメモリに直接マップすることを望んでいました。彼が与える例は、次のようなファイルシステムエントリです

struct {
  int inode;
  char name[14];
};

彼は構造体に 2 バイトの整数値とその直後に 0 で終わる文字列を含めたいと考えていましたが、name配列へのポインターをどうすればよいかわかりませんでした。構造体の一部として格納する必要があるのか​​、それとも格納する必要があるのか​​ということです。別々に?別々の場合、どこに保管すればよいですか?

彼は、配列ポインターを完全に取り除くことで問題を解決しました。配列の最初の要素へのポインター用のストレージを確保する代わりに、彼はポインター値が配列式自体​​から計算されるように言語を設計しました。したがって、C で配列を次のように宣言すると、

T arr[N];

タイプの N 要素のみTが割り当てられます。


            +---+    
  arr[0]:   |   | 
            +---+
  arr[1]:   |   |
            +---+
  arr[2]:   |   |
            +---+
             ...
            +---+
  arr[N-1]: |   |
            +---+

symbol にバインドされた別のストレージはありませんarr&arrこれが、式とarr両方が同じ(配列の最初の要素のアドレス) を生成する理由です。ただし、2 つの式の(それぞれT (*)[N]T *) は異なります。これが、配列式が代入の対象にならない理由です。に値を割り当てるものは何もありません。

于 2013-10-03T18:48:04.793 に答える
0

特に理由はありませんが (歴史的な事故以外に)、C では配列を直接割り当てることはできません。要素を 1 つずつコピーする (または memcpy を使用する) 必要があります。

memcpy(ethernet_hdr->ether_shost,original_dhost,sizeof(original_dhost));
于 2013-10-03T16:11:27.797 に答える
0

配列は、固定数の連続するオブジェクトへのポインターです。したがって、目的の動きを実現するには、memcpyを使用します。

于 2013-10-03T16:11:54.600 に答える
0

構造体エントリは配列型のフィールドを宣言していますが、コンパイラはそれがポインタであると言っています

配列が参照されると、ほとんどの場合、ポインターに減衰する (暗黙的に変換される) ためです。

ethernet_hdr->ether_dhost に割り当てようとすると、次のエラーが発生します。

もちろん。配列は変更可能な左辺値ではありません。それらを「割り当て」たい場合は、直接行うことはできません。memcpy()代わりに使用してください。

于 2013-10-03T16:12:32.777 に答える
0
于 2013-10-03T17:07:23.513 に答える