ここにはいくつかの問題があります。
まず、配列式は代入の対象にならないことがあります。のようなものを書くことはできません
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 *
) は異なります。これが、配列式が代入の対象にならない理由です。に値を割り当てるものは何もありません。