3

C/C++ コードの ifdef に直面して、標準コード複雑度メトリック (LOC、McCabe 循環的複雑度、Halstead メトリックなど) がどのように計算されるのか疑問に思っていました。

ifdef を無視すると、次のような構文エラー (または型エラー) が発生する可能性があります。

  1. #ifdef FOO
  2. for(i = 0; i < x; i++) {
  3. #そうしないと
  4. for(i = 0; i < y; i++) {
  5. #endif
  6. printf(...)
  7. }

行 1、3、および 5 が無視されると、結果のコードには 1 つのループが別のループの内側にあり、'}' が欠落しています (したがって、構文エラー)。

#ifdefs が考慮される場合、バリアントごとに 1 つの結果メジャーが必要になります (この場合、FOO が定義されている場合に 1 つ、FOO が定義されていない場合にもう 1 つ)。ただし、このようなアプローチは、実際には簡単に爆発する可能性があります。

http://manpages.ubuntu.com/manpages/natty/man1/pmccabe.1.htmlを見ると、マンページは次のように報告しています。

pmccabe の解析では、すべての cpp プリプロセッサ ディレクティブが無視されます - プリプロセッサがコードをマングルした後の複雑さではなく、コードの外観の複雑さを計算します。getchar(3) のような単純なものがマクロに展開され、複雑さが増すため、これは特に重要です。

しかし、前述したように、この方法ではコード エラーが発生し、計算プロセスが妨げられたり、誤った値が返されたりする可能性があります。

ツールはこの問題をどのように克服しますか?

よろしく。

4

3 に答える 3

2

その構成を次のように書き換えると

#ifdef FOO
# define LOOPEND x
#else
# define LOOPEND y
#endif

またはそのようなもの、問題はないはずです。

それをしたくなく、複雑度チェッカーがプリプロセッサを理解していない場合は、FOO定義済みとFOO未定義の両方でプリプロセッサの出力に対して実行し、生成される値の最大値を取得して取得できます実際の複雑さの下限。gcc -EGCC では、プリプロセッサは;で呼び出されます。他のコンパイラにも同様のオプションがあります。

(もちろん、この CPP の魔法がたくさんあれば、指数関数的な数の可能性が残されます。しかし、それはプリプロセッサを使用するために支払う代償です。同じことがテストにも当てはまります。)

于 2013-02-25T16:16:14.270 に答える
1

メトリック計算機の多くは、完全なパーサーまたは適合するパーサーを使用せず、代わりに (おそらく) 翻訳の最初の数フェーズを実行してから、キーワードを探します。

あなたが説明したような完全な構文の問題を見ていないので、それらをブロックしないでください。ただし、他の方法で脆弱になることはあります。実際、堅実な製品コードでシクロ 2.0 が完全に失敗するのを見てきました。

于 2013-02-25T16:18:15.400 に答える
0

大規模なプロジェクト (20 行の「実験」ではなく)#ifdefでは、コードの実際の複雑さに影響を与える類似の量はかなり最小限になると考えていたでしょう。そのような式のほとんどが全体的なスコアにあまり影響を与えていない孤立したユニット。

しかし、そうです、パーツ内に大量で#ifdef複雑な小さなコード セットがある場合、大きなエラーが発生する可能性があります。#ifdefコードを手動で検査すると、これがわかります。

于 2013-02-25T16:20:22.660 に答える