2016/05/23

[c99]C99のinlineで悩む

構造体の中身をあまり意識させたくないので、引数に構造体のポインタをもらって要素をreturnするだけの関数を作った。
でもまあ、こういうのにわざわざ関数ジャンプしてほしくないよな、たぶん最適化してくれるだろうな、と思うのだが、ヘッダでinline指定して実装もそこに書いた。

そしたら、gccでビルドするとリンクエラーになるのですよ。
nmで見てみてもU扱いだから、他でリンクする必要ありと思っている。
いやー、classのメンバ関数だってinlineにするときはヘッダに実装まで書くのに、なんでここでリンクエラーになるの??

 

調べると、GCCのinlineはC99のinlineとは違うということだった。
static inlineは一緒で、

GCC:inline   -->  C99:extern inline
GCC:extern inline --> C99:inline

そういえば、そういうことを言っていた気がするが、いままでstatic inlineしか使っていなかったので気にしていなかったようだ。

 

こちらによると、-std=c99をつけるとC99の仕様に合うらしい。
さらには、GCCのv5からはデフォルトでC99仕様になっているらしい。
Using extern inline · ytomino/headmaster Wiki

あれ・・・じゃあ、私のが動かないのはGCCだからじゃなくて、inlineの書き方が違うからということか。

 

では、以下はGCC v5で、念のため-std=c99まで付けた場合ということで進める。

 

ヘッダに「inline」で関数実装を書くと、発生するのは、undefined referenceだ。
それを「extern inline」にすると、発生するのは、multiple definition。

externが付いていると「よそでも参照するよ」という関数がincludeしたファイルの数だけできるので、multiple definitionになる(includeしたファイルが1つしかないならエラーにならない)。
付いていないと、それは単なる宣言と見なされてしまい、undefinedになるということか?

 

なので、ヘッダに実装を書いてしまいたいのであれば「static inline」にして、ファイルごとにstatic展開してしまうしかないか。
でも、そこまでやるんだったら、インラインになるかどうかよくわからんinlineを使うよりもマクロ関数にしてしまいそうだ。

 

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472fj/BABEGBHC.html
ここを見ると、ヘッダに「inline」で関数実装を書いているのよねぇ。
「コンパイラのコーディング慣行」の章だから、「他は知らんけどarmccはこうなんだよ」ということだろうか。


あれ・・・なんかまだ認識を間違っているみたい。

ヘッダにinlineの宣言だけを書いて、実装をソースに持っていくとコンパイルの警告が起きるようになった。
「inline function 'xxx' declared but never defined」だ。

考えたら当たり前で、単にプロトタイプ宣言をヘッダに持っていっただけだからだ。
inlineが付いているから、同じスコープ内に関数定義がないということで警告しているのだろう。

だったら、ヘッダに定義を書いていたらうまくいってよさそうなのだけど、これはダメなのだ。
ヘッダに実装を書かずextern inlineにし、ソースにinline定義を書くと、ヘッダのextern inlineについては警告するが、リンクが通る。
どう並び替えても、あまり結果が変わらない。

 


使うのはstatic inlineくらいかなぁ、という気持ちになってきた。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。