プログラマのつれづれなるままにプログラマのつれづれなるままに音宮志久が思ったことなどをネタにします。プログラムネタ・数学ネタがメインです。構造体の値渡しとレジスタ構造体の値渡しとレジスタコメントを残すおそらくほとんどのプログラマでさえ気にしない話題です。C言語でプログラムを書くとまれに構造体を値渡しで関数呼び出しする例が出てきます。WinAPIでもSetFilePointerExのようにLARGE_INTEGER構造体を引数で呼び出すパターンがあり、これに該当します。このとき、どのように対象の関数を呼び出すのでしょうか?なお、関数の呼び出し規約に関する基礎的な情報は理解しているものとします。(cdecl、stdcall、fastcallでのスタック・レジスタの使い方(この記事を参照のこと)一応記事の補足をしておくと、x86のfastcallは第一引数がecx、第二引数がedxになります。x64の場合は、整数の第一引数がrcx、第二引数がrdx、第三引数がr8、第四引数がr9を使用します。ちなみに、x64の場合に限り、浮動小数でも第一引数から第四引数まではレジスタ経由になります。(xmmレジスタに浮動小数が入っていることになる)一応ただVisualStudioで調べた結果なので最適化とか値渡し時の速度とか気にする人でない限り意味がない情報だと思います。速度を気にするならほとんどが参照渡しかポインタを使うことになると思います。(C++上で参照渡しとポインタの値渡しは記述が異なるだけで命令上は同じ物(対象のオブジェクトのアドレス)を扱うので、引数はレジスタ幅の整数型一つになります)構造体がレジスタサイズよりも大きい、もしくはレジスタ経由で引数を渡さない場合たとえば、以下のようなパターンです。0;f(n);}この場合は単純に引数のメモリ位置に構造体のデータがそのままあるように転送されて呼び出されます。}のように関数を宣言したときと同じようなメモリ配置になります。(単にメモリ領域がスタック上に確保されてそのまま値がコピーされるのだよ~という意味を言っているだけで、実際にこうなるわけではありません)構造体がレジスタサイズ以下であり、引数をレジスタ経由で渡すように定義されているとき以下のようなパターンが該当します。0;f(n);}このときは、fastcallの呼び出し規約を使って、構造体のデータがそのまま(構造体をメモリからみた一つの整数値と仮定して)ecxレジスタに転送された後呼び出されます。単体でaとかbの値を取り出すときには呼び出し先でビットシフトなどが使用されることになります。構造体がレジスタサイズ以下であるが、複数引数が混じるときこれに関してはx64とx86で異なった動きをしていました。0;f(n);}このとき、呼び出しの状態がちょっと違って、x86の場合、edxを使わずにそのまま構造体のデータをメモリ上に転送していました。x64の場合はrdxに転送しているのでこれはx64の呼び出し規約の通りになっていました。構造体がレジスタサイズより大きいが、複数引数があるときx86では上記の例でほぼ説明がついていますのでx64の例だけです。3となっているのに対して構造体の部分だけちゃんとメモリ経由で渡されているんですね・・・。}と(メモリ上は)こんな関数宣言っぽくなります。何ともおもしろい仕様ですね。プログラム解析では知っておいた方がいいかもしれない情報ですが関数呼び出し時に構造体の呼び出しをどう処理するか、を定めた情報ですので重要かもしれません。それ以外のコンパイラだとどういう風に反応するのか、それはよく知りません。内部的な呼び出しだけならこれ以外の方法でも実は問題ないためです。コメントをキャンセルメールアドレスが公開されることはありません。志久プログラムネタや思いついたり世間で話題になっている数学ネタを解説したりしています。プログラマとしては今年度(つまり2020年3月)までの復帰となるか、完全復帰となるか、別の仕事に戻るかは運と実力次第。ちなみに教育系のプログラムでもOKです。アクセスカウンタアクセス数:スポンサーリンク。