今週、ここで興味深い問題に遭遇しました。
16 ビットのデータ アドレスと 32 ビットのコード アドレスを持つハーバード アーキテクチャの組み込みプラットフォームで C を使用しています。
この問題は、関数ポインターを操作しているときに発生します。次のようなコードがある場合
if (fp) fp();
また
if (fp != 0) fp();
すべて順調。
ただし、次のようなコードがある場合
if (fp != NULL) fp();
次に、NULL
が として定義されているため(void *) 0
、コンパイラ (この場合は gcc) は a) 警告を出さず、b) 32 ビット比較ではなく、関数ポインタに対して 16 ビット比較を行います。関数ポインターがたまたま 64k の境界上にない限り、下位 16 ビットはすべて 0 です。
現時点では、NULL に対する明示的なチェックを含む大量のコードがあります。それらのほとんどはデータ ポインターになりますが、一部は関数ポインターになります。3000 を超える結果を簡単に grep し!= NULL
たり、明らかにしたりしましたが、その多くは手動で確認する必要がありました。== NULL
したがって、今私たちが望むのは次のいずれかです
関数ポインタ (データ ポインタではない) が比較されるすべてのケースを見つける方法 (代わりに、32 ビット 0 として定義する FP_NULL と比較することができます)、または
正しいことを行うように NULL を再定義します。
(または、gcc ポートを更新して、このケースを検出して正しく処理すると思います)。
1で機能するアプローチは考えられません。2で考えられる唯一のアプローチは、NULLを0関数ポインターとして再定義することです。これは、データポインターに対する比較の大部分にとって非常に無駄になります。(32 ビットの比較は 4 命令、16 ビットの比較は 1 命令です)。
何か考えや提案はありますか?