私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「構造体のアライメント」(CodeIQ)を参照してください。
【概要】
構造体の中に、いくつかの要素が入っています。
最後の要素の先頭アドレスが、構造体の先頭から何バイトあとにあるのかを計算して下さい。
ただし、構造体の先頭アドレスは(幸運なことに)16の倍数になっています。
【入出力】
入力は
SDIL
のようになっています。
構造体の中にある要素を示す記号が、アドレス順に区切り文字なしで並んでいます。
各記号の意味は、下表のとおりです:
例えば、CMの様になっていた場合、先頭のアドレスにはCが示す要素が入っています。
記号 サイズ(バイト数) 先頭アドレスの制限 C 1 なし S 2 偶数アドレス I 4 4の倍数アドレス L 8 4の倍数アドレス D 8 8の倍数アドレス M 16 16の倍数アドレス
その後には 15byte のパディング(変数としては使われない詰め物)が入っていて、Mが示す要素はその後に続くことになります。
出力は、SDIL の示す構造体の先頭アドレスから 20 バイト先に末尾の要素があるので
20
のような感じです。
構造体のサイズではなく、最後の要素の先頭アドレスであることに注意して下さい。
【例】
入力 出力 メモリイメージ(.はパディング) SDIL 20 SS......DDDDDDDDIIIILLLLLLLL CM 16 C...............MMMMMMMMMMMMMMMM CSILDC 24 C.SSIIIILLLLLLLLDDDDDDDDC
【補足】
不正な入力に対処する必要はありません。
Lのアライメントは 4 の倍数です。8 の倍数ではありません。
データのリオーダーはないものとします。
入力文字列の長さは、1 文字以上 16 文字以下です。
実際のアライメントについてはWikipedia の記事が参考になるかもしれません。
Rubyで解答しています。
#!/usr/bin/ruby def solve(struct) pos = { "C" => {"size" => 1, "st" => 1}, "S" => {"size" => 2, "st" => 2}, "I" => {"size" => 4, "st" => 4}, "L" => {"size" => 8, "st" => 4}, "D" => {"size" => 8, "st" => 8}, "M" => {"size" => 16, "st" => 16}, } st = 0 ed = 0 struct.split("").each_with_index{|c, i| if ed % pos[c]["st"] != 0 then st = (ed / pos[c]["st"] + 1) * pos[c]["st"] else st = ed end ed = st + pos[c]["size"] # printf("st=%d, ed=%d\n", st, ed) } return st end # main while line = gets line.strip! next if line.empty? p solve(line) end
特に難しいところはなく、素直にやればできます。
2番目以降の要素の開始位置をどう計算するかだけです。
一つ前までの要素の終了位置を次の要素の「先頭アドレス制限」で割り、その端数を切り上げた値に「先頭アドレス制限」を掛けた値が開始位置になるので、それに「サイズ」を加えたものが次の終了位置になります。これを繰り返し最後の要素の開始位置が答えになります。
例えばCMの場合、次のようになります。
Cの開始位置は0、終了位置は1。
終了位置1をMの「先頭アドレス制限」で割って端数を切り上げると1なので、1に「先頭アドレス制限」の16を掛けるとMの開始位置は16、終了位置は16+16で32。
Mが最後の要素なので答えは16。
入力値をsolve()に渡し、結果を印字します。
問題を解きます。
posは記号に対し、サイズと先頭アドレス制限の組みを値とした連想配列です。
stは開始位置、edは終了位置を保持する変数で初期値は共に0です。
入力値を1文字ずつ取り出します。
edをposの対応する記号の「先頭アドレス制限」で割って割り切れたら開始位置までパディングされないのでそのまま、割り切れなかった場合は「先頭アドレス制限」で割り、その端数を切り上げた値に「先頭アドレス制限」を掛けた値を開始位置にします(16〜20行目)。
終了位置はstに記号に対応するサイズを加えた値に更新します(21行目)。
最後まで処理した時のstが答えになるのでそれを返却します。
#include出力は次のようになります。struct hoge { char a; short b; int c; long d; float e; double f; }; int main(void){ struct hoge* h = (struct hoge*)0; printf("a=%p\n", &(h->a)); printf("b=%p\n", &(h->b)); printf("c=%p\n", &(h->c)); printf("d=%p\n", &(h->d)); printf("e=%p\n", &(h->e)); printf("f=%p\n", &(h->f)); return 0; }