移植性のあるCプログラミング

C言語を使って移植性の高いプログラミングを行うのは簡単ではありません。このブログでは、筆者自身の備忘録を兼ねて、移植性のあるプログラミングのノウハウを記録していきたいと思います。
<< June 2017 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 >>
 
PROFILE
RECOMMEND
Cプログラミング診断室―さらに美しく健康的なプログラムのために
Cプログラミング診断室―さらに美しく健康的なプログラムのために (JUGEMレビュー »)
藤原 博文
私がある程度C言語でプログラミングができるようになった頃、この本の旧版を読みました。
非常に辛口の内容であり、読者によっては嫌悪感を抱く方もおられるかもしれませんが、「Cプログラミング診断室」は、C言語に関する数少ない有益な書籍のひとつです。もっとも、元の内容がかなり古いため、今となってはやや時代遅れとなった部分もあります。しかし、それを差し引いても、十分に読む価値のある一冊です。
RECOMMEND
新ANSI C言語辞典
新ANSI C言語辞典 (JUGEMレビュー »)
平林 雅英
まだC言語を覚えたてだった頃、この本の前の版である「ANSI C言語辞典」がボロボロになるまで活用しました。私が購入したC言語関連の書籍の中では、最もコストパフォーマンスが高かったと思います。
あまりにもボロボロになったので、改訂版にあたる、この「新ANSI C言語辞典」を購入しました。旧版を最初に手にしてから10年以上経ちますが、今なお手放すことができない必携の一冊です。
ARCHIVES
RECENT COMMENT
RECENT TRACKBACK
MOBILE
qrcode

無料ブログ作成サービス JUGEM
 
スポンサーサイト

一定期間更新がないため広告を表示しています


- | | - | -
関数のアドレスと空ポインタの比較
最近のホットな話題なので、忘れないうちに投稿しておきます。関数のアドレスと空ポインタの比較についてです。

フック関数など、特に必要がなければ、実体は何も定義しないまま、関数のシンボルを0番地に配置しておき、必要になった時点で実際の関数で置き換えるといった技法がよく使われます。

具体的には、GNUのリンカスクリプトでPROVIDEによってウィークなシンボルを定義したり、GCCのweak alias属性を付けたり、インラインアセンブラを使ったり、シンボルを0に配置するアセンブリ言語のソースとCの関数定義を使い分けたりといった具合です。

このとき、フック関数を呼び出す箇所では、関数が存在するかどうかを調べるために、0(空ポインタ)との比較を行うことになります。

extern void hook(void);

if (hook != 0)
  hook();

ところが、標準Cでは、いかなる関数へのポインタも空ポインタと等しくならないことが、言語仕様上保証されています。結果として、hookのアドレスを実際に調べるまでもなく、hook != 0は常に真であると判断しても、本来であれば問題がないわけです。

結果として、最適化オプションを付けてコンパイルすると、hook != 0の部分は常に真として扱われ、実際にはhookが0番地であり、関数定義が存在しないにも関わらず、hook関数を呼び出してしまうといった事態を招きます。

元々が、通常のCの使い方から逸脱した技法で、処理系に依存した方法を使った結果として起こる問題なのですが、こんな場合でも、極力移植性のある記述を行わなければならないことがあります。
この問題を回避する方法はいくつか検討されたのですが、最終的に落ち着いた方法だけを紹介することにします。

extern void hook(void);
void (* volatile func)(void) = hook;

if (func != 0)
  (*func)();

ここで、funcは関数へのポインタを格納するための変数なのですが、volatileが付いているところがポイントです。volatileが付いていると、コンパイラが知らない方法でfuncの値が変化するかもしれないため、func != 0が常に真であるとみなすことができなくなります。結果として、func != 0の評価は期待通り行われることになります。

スポンサーサイト

- | 01:09 | - | -
コメント
from: k_satoda   2006/06/02 9:17 AM
最初のコードでの hook の宣言は
extern void hook(void);
の間違いではないですか?
元の記事のようにポインタ変数として宣言したのなら 0 との比較が消えることは無いはずです。
from: たかぎ   2006/06/02 9:41 AM
> 最初のコードでの hook の宣言は
> extern void hook(void);
> の間違いではないですか?

ご指摘ありがとうございます。
間違いでした。直しておきます。
コメントする









 
トラックバック
この記事のトラックバックURL
http://portable-c.jugem.jp/trackback/14
アセンブリ言語機械語を簡便に記述するためのプログラミング言語。アセンブラによって機械語に変換される。 アセンブリ言語のプログラムには、ニーモニックと呼ばれる命令の列を記述する。 ニーモニックは基本的に機械語の命令と一対一対応するものである。ラベルなど
プログラム 用語辞典 | 2006/08/13 10:34 AM
たまに来ますのでよろしくお願いします。
nznsc | 2006/11/08 6:22 AM