2

私には機能があります

void *custom_get_value(ObjectPtr) 

この関数は従来、NULL を返すために使用されることはありませんでした。次のいずれかの値を返すことができます。

uint32_t
int32_t 
uint64_t 
int64_t
uint8_t

関数が NULL を返すことはなかったので、それを行うコードがたくさんあります。

       *(uint32_t*)custom_get_value(ObjectPtr)

                    OR

      *(uint64_t*)custom_get_value(ObjectPtr) 

最近、の動作を変更することを決定しました

void *custom_get_value(ObjectPtr) in such a way that it can return NULL.So all occourances of the above scenario (de-referencing to specific types without checking the return value) can result in segmentation fault.

マクロを使用して、戻り値が返されるコード内のすべての場所を特定できますか?

void *custom_get_value(ObjectPtr)

はチェックされていません。はいの場合、どうすればよいですか?

4

2 に答える 2

2

値が返された後にその値がどうなるかを追跡できるマクロを簡単に作成することはできません。これは、データ フローの分析がプリプロセッサの能力を超えているためです。ただし、このような状況に役立つように設計された便利な手法があります。これは、チェックする関数を自己参照マクロとして定義することです。

#define custom_get_value(...) (0, custom_get_value(__VA_ARGS__))

この例はそれ自体では何もしませんが、便利なことを示しています: マクロ名が独自の置換リストの一部として表示されると、名前のネストされたオカレンスは「青く塗られ」、2 回目は展開されません。したがって、既存の関数名をマクロとして定義することにより、関数の既存のすべての呼び出しを「ラップ」(または「アドバイス」) することができます。オリジナル召喚。

次に、いくつかのオプションがあります。

#define custom_get_value(...) ({ \
    _Pragma("message \"custom_get_value called\""); \
    custom_get_value(__VA_ARGS__); \
})

...GCCまたはClangを使用している場合custom_get_valueは、コンパイル時に呼び出されるすべてのポイントのファイルと行番号をリストする必要があります。(両方とも#pragma message、ステートメント式の形式は非標準の GCC 拡張機能です。しかし、古い呼び出しをクリーンアップするときにのみこれを使用する場合は、おそらく問題にはなりません。すべての呼び出しがチェックされたら、非標準のコードを削除できます。)

または、代わりにランタイム メッセージを適用します。

#define custom_get_value(...) \
    custom_wrap(custom_get_value(__VA_ARGS__), __FILE__, __LINE__)

void * custom_wrap(void * val, char * f, int l) {
    printf("custom_get_value called in %s on line %d\n", f, l); return val;
}

...これは、関数が呼び出されるたびにメッセージを出力するのに夢中になりますが、少なくとも標準です。

結果のポインターが非 null であることを保証する関数ですべての呼び出しをラップすることもできますが、これはおそらくこの状況に対処する最善の方法ではありません。

于 2014-05-11T00:05:05.633 に答える
0

新しい関数に名前を付けてcustom_get_value_ex、古い関数を削除します。そうすれば、コンパイラは古い関数のすべての使用を非常に親切に示してくれるので、それらを確認できます。

一般に、すでに使用されている関数のセマンティクスを変更する場合は、とにかく関数へのすべての呼び出しを確認することをお勧めします。

おそらく、これらの呼び出しのいくつかをより保守しやすいラッパーでラップすることができます。

inline uint32_t custom_get_uint32(.....) 
{  
     void *value = custom_get_value(.....);
     if ( !value )
          return 0;   // or some other error handling
     return *(uint32_t *)value;
}

その後、custom_get_value再度変更する場合は、このラッパーを fox するだけで済みます。

興味のあるアイテムを取得するための関数を用意すると、さらに整頓されます。

inline uint32_t get_propeller_setting(.....)
{
     void *value = custom_get_value(PROPELLER_SETTING,........)
     // ....
}

次に、各値が null ポインターを返すときの特定の処理を行うことができます。

于 2014-05-11T03:14:22.540 に答える