miyuriの日記: paddingを考慮しない 4
日記 by
miyuri
この辺の流れ。
例えば、
struct ip_header;
struct tcp_header;
っていうのがあるとして、IPヘッダ長は20[octet]固定の場合で。
struct ip_header *ip_packet;
struct tcp_header *tcp_packet = (struct tcp_header *)(ip_packet+sizeof (struct ip_header));
って感じにしてしまうって事なのかな。
ヘッダ+データの場合、大抵はデータ位置を指す値をヘッダに含んでいるから、こういう書き方をしないよね。
okky氏の『padding だけでも結構頭痛が』っていうのは、どういう事なのだろう。
危険危険 (スコア:2)
structureのサイズは、環境によって変わるからそのコードは(v6ヘッダの様にサイズ固定でも)危険。
#ip_packetはunsigned char *で定義されてないと、400バイトくらい先をみちゃいますよお
お代官様もおっしゃっているが… (スコア:1)
IP header は長いから例として不適切なのだが…例えば、
話を簡単にするために、上記の部分だけに限定する。
よくあるのが、Ethernet の ペイロードの先頭へのポインタを p とした時に、
のように型キャストして、それ以降各要素を
のようにアクセスする、というコードだ。ちょっとふるい目のネットワークプログラミング関係の本には、こうしろ、と出ている。
これが正しいためには sizeof( ip_header ) が 20byte でなくちゃいけない。つまり上記の構造体は padding が一切入っちゃいけないのだ。ところが、2^n alignment …それも 32bit alignment にすると非常に座りが良いCPU…大抵のRISC CPUはそうだが…用のコンパイラは、ちゃんとオプションを指定しないと、実体としてこうなる。
sizeof( ip_header )は 40byte にもなる。各変数の後ろに来る alignment 用 padding が悪さをしまくる。例えば
の結果は、本来の場所よりも 20byte ほど後ろを指す事になる。
# もっと贅沢なCPU用コンパイラになると、全体を64byteの倍数に合わせようとしやがって…
判ると思いますが、一般には alignment をきちんと合わせたIOはCPUからみて高速になります。なので、特に指示がないなら、padding を入れるのは妥当。本当は構造体から数字を1つづつ取り出して、1byteづつ unsigned char の配列へ代入していく/取り出して構造体のメンバーに代入していくのが、C言語における唯一確実なコードなのです。遅すぎないか…という噂もありますが、実は言うほど遅くなかったりもします。コード的にはすごく「いらいらする」コードになりますが。
で、移植性を多少犠牲にしてでも…となってしまうのですが、そのコードを後で
「まさにお前らが切り捨てた移植性問題を抱えた環境」
に移植する側の身にもなってみやがれ!! という状態に陥るのです。なにしろ、プログラミング言語レベルでは一切のバグがないまま、構造体のサイズに対する仮定が崩れるので、どの構造体がどうずれていて、それは正しいのか間違っているのかさっぱり…
上記はそれでも一応 IP header なので何とかなりますが、独自プロトコルの独自ヘッダーなど持って来られた日には、実は大元のコードが作られていたコンパイラの癖のせいでじつは padding が入っているのが正しいだとかいうことに… orz
fjの教祖様
Re:お代官様もおっしゃっているが… (スコア:2)
ありがとう。
Re:お代官様もおっしゃっているが… (スコア:2)
引用部分が変になっているけど、適当に解釈してください。