struct obj *get_obj(...);
そして
void get_obj(..., struct obj**);
ここでは効果がないように見えますが、なぜ2番目の方法を強調したのですか? そして、ここにあります。 最初は、オブジェクトへのポインタ、または見つからない場合はNULLを返すことができます。 ただし、プログラマには疑問があります。メソッド内の例外はどうでしょうか。 はい、はい、C言語の
struct obj *get_obj(..., int *ret); int get_obj(..., struct obj **);
しかし、現在のタスクは、関数の引数の数を減らすことです。これは、実行速度とスタックで消費されるメモリ量の両方に大きく影響するためです(OSカーネルについてですよね?:-))。
このため、そのようなソリューションが発明されました。 void *は依然として数値なので、可能な値を3つのセグメントに分割します(32ビットの場合を考慮してください)。
- 0x00 ... 0x10
- 0x11 ... 0xffffffff-MAX_ERRNO
- 0xffffffff-MAX_ERRNO + 1 ... 0xffffffff
最初はNULLポインター、2番目は通常のアドレススペース、3番目は無効なポインターまたはエラーコードです。 したがって、検証のためにいくつかのマクロが登場しました。
ZERO_OR_NULL_PTR(); IS_ERR(); IS_ERR_OR_NULL();
そして人々はそれらを使い始めました!
結果のプロトタイプは次のようになりました。
struct obj *get_obj(...);
そして使用例:
struct obj *get_obj(...) { struct obj *obj = malloc(sizeof(*obj)); int ret; if (!obj) return ERR_PTR(-ENOMEM); ret = do_smth(obj, ...); if (ret) { free(obj); return ERR_PTR(ret); } return obj; } int whatever(...) { struct obj *obj = get_obj(...); if (IS_ERR(obj)) return PTR_ERR(obj); printf("Cool object %p\n", obj); return 0; }
ただし、たとえば、このカーネルアセンブリでオフになっているカーネルの一部の機能をオブジェクトが担当している場合など、NULLが有効なリターンであるコードの部分に対してIS_ERR_OR_NULLマクロを誤って使用するため、このアプローチには問題もあります。 次に、NULLポインターが返されますが、これは別の方法で処理する必要があります!