7

私は現在 C でコーディングしており、アプリケーションのフローを時々追跡できるように、たくさんの printfs を持っています。問題は、他のものよりも詳細が必要な場合があるため、通常は C コードのコメント化/コメント解除に時間を費やして、適切な出力を取得できるようにすることです。

Java または C# を使用する場合、通常、アスペクトを使用することで、両方の実装コードをロギング ロジックから分離できます。

この問題を回避するために C で使用する同様の手法はありますか?

オンまたはオフのいずれかになる可能性のある DEBUG というフラグを設定できることを知っているので、printfs を表示または非表示にするたびに、コード全体をコメント/コメント解除する必要はありません。問題は、コード内のログ ロジックも削除したいということです。

CI の代わりに C++ でコーディングしていたら、もっと良くなるでしょうか?

編集

AspectC++ があるようですので、C++ には解決策があるようです。Cはどうですか?

ありがとう

4

6 に答える 6

11

IME では、ログを記録したいアルゴリズムからログを分離することはできません。ログ ステートメントを戦略的に配置するには、時間と経験が必要です。通常、コードはその有効期間全体にわたってログ ステートメントをアセンブルし続けます (漸近的ですが)。通常、ロギングはコードとともに進化します。アルゴリズムが頻繁に変更される場合、通常はロギング コードも変更されます。

できることは、ロギングをできるだけ目立たないようにすることです。つまり、ログ ステートメントが常にアルゴリズムの読み取りを妨げないワンライナーであることを確認し、ログ ライブラリを完全に理解する必要なく、他のユーザーが追加のログ ステートメントを既存のアルゴリズムに挿入できるようにします。

要するに、文字列処理を扱うのと同じようにロギングを扱います。それを素敵な小さなライブラリにラップします。これは、ほぼどこにでも含まれて使用され、そのライブラリを高速にし、使いやすくします。

于 2010-11-14T16:48:15.847 に答える
5

あまり。

可変長マクロが利用できる場合は、次のようなゲームを簡単にプレイできます。

#ifdef NDEBUG
    #define log(...) (void)0
#else
    #define log(...) do {printf("%s:%d: ", __FILE__, __LINE__); printf(__VA_ARGS__);} while(0)
#endif

より細かい粒度でオンとオフを切り替えることができるログを作成することもできます。

#define LOG_FLAGS <something>;

#define maybe_log(FLAG, ...) do { if (FLAG&LOG_FLAGS) printf(__VA_ARGS__);} while(0)

int some_function(int x, int y) {
    maybe_log(FUNCTION_ENTRY, "x=%d;y=%d\n", x, y);
    ... do something ...
    maybe_log(FUNCTION_EXIT, "result=%d\n", result);
    return result;
}

関数の戻り値を直接取得できないため、各関数からの戻り値を 1 つだけ許可するのは明らかに面倒です。

これらのマクロと呼び出しはいずれもprintf、実際のログ形式とターゲットをビジネス ロジックから分離できるようにする何か (他のマクロ、または可変個引数関数呼び出し) に置き換えることができますが、何らかの種類のログが実行されているという事実はできません。本当に。

Aspectc.org は、AOP をサポートする言語拡張機能を備えた C および C++ コンパイラを提供すると主張しています。それがどのような状態にあるのかはわかりません。もちろん、それを使用する場合、C (または C++) を実際に書いているわけではありません。

C++ には複数の継承があることに注意してください。これは、分野横断的な懸念に役立つ場合があります。十分な数のテンプレートがあれば、驚くべきことを行うことができます。おそらく、ある種のジョイン ポイントを可能にする独自のメソッド ディスパッチ システムを実装することさえできますが、これを行うのは大変なことです。

于 2010-11-14T16:34:13.763 に答える
4

GCC では、可変長マクロを使用できます: http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.htmldprintf()任意の数のパラメーターで定義することが可能になります。

追加の隠しverbose_levelパラメータを使用して、メッセージをフィルタリングできます。

この場合、ログ ロジックには次のものが含まれます。

dprintf_cond(flags_or_verbose_level, msg, param1, param2);

残りのコードから分離する必要はありません。

于 2010-11-14T16:33:14.587 に答える
1

うーん、これは去年の夏に C++ プロジェクトに取り組んでいたときに遭遇した問題に似ています。これは完全に防弾でなければならない分散型アプリであり、その結果、面倒な例外処理が大量に発生しました。10 行の関数は、例外を 1 つまたは 2 つ追加するまでにサイズが 2 倍になります。これは、それぞれが長い例外文字列と関連するパラメーターから文字列ストリームを構築し、実際には 5 行後に例外をスローするためです。

そのため、すべての例外メッセージを 1 つのクラス内に集中できるという意味で、小さな例外処理フレームワークを構築することになりました。起動時に (おそらくパラメーター化された) メッセージを使用してそのクラスを初期化すると、throw CommunicationException(28, param1, param2)(可変引数) のようなものを記述できるようになりました。私はそのために少しの高射砲をキャッチすると思いますが、コードは無限に読みやすくなりました. たとえば、唯一の危険は、メッセージ #2​​8 ではなくメッセージ #2​​7 でその例外を誤ってスローする可能性があることです。

于 2010-11-14T16:47:07.297 に答える
1

フラグと適切なロジックはおそらくより安全な方法ですが、コンパイル タイプでも同じことができます。すなわち。#define と #ifdef を使用して、printfs を含めたり除外したりします。

于 2010-11-14T16:29:35.757 に答える
0
#ifndef DEBUG_OUT

# define DBG_MGS(level, format, ...) 
# define DBG_SET_LEVEL(x) do{}while(0)

#else

extern int dbg_level;
# define DBG_MSG(level, format, ...)              \
   do {                                           \
      if ((level) >= dbg_level) {                 \
          fprintf(stderr, (format), ## __VA_ARGS__); \
      }                                           \
   } while (0)
# define DBG_SET_LEVEL(X) do { dbg_level = (X); } while (0)

#endif

##before は、実際の余分な引数がない場合に実際に正しいコードに変換__VA_ARGS__する GCC 固有のものです。, __VA_ARGS__

通常の関数を呼び出すときのように、ステートメントを使用するときにステートメントの後にdo { ... } while (0)置くだけです。;

派手になりたくない場合は、デバッグレベルの部分を廃止できます。これにより、必要に応じてデバッグ/トレースのレベルを変更できるようになります。

print ステートメント全体を、デバッグ レベルに関係なく呼び出される別の関数 (インラインまたは通常の関数) に変換し、内部で印刷するかどうかを決定することができます。

#include <stdarg.h>
#include <stdio.h>

int dbg_level = 0;

void DBG_MGS(int level, const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    if (level >= dbg_level) {
        vfprintf(stderr, format, ap);
    }
    va_end(ap);
}

*nix システムを使用している場合は、 を参照してくださいsyslog

いくつかのトレース ライブラリを検索することもできます。私が概説したものと同様のことを行うものはいくつかあります。

于 2010-11-14T22:44:58.563 に答える