2

ファイルを区別する必要があるプロジェクトを作成しました。ファイルは、Linux デーモン (C で記述) と単純な Linux プログラム (C++ で記述) に属しています。これら 2 つのプロジェクトは、2 つの共有ファイル (helpers_functions) を使用しました。デーモンとプログラムのロギング システムは異なります。デーモンはファイルに書き込み、プログラムは標準出力に。

両方のプログラムの共通関数 (helper_functions ファイル内) で何かをログに記録したい場合に問題が発生します。これがプログラムAまたはプログラムBであることを、パラメーターを介して渡したくありません。

g++ フラグ-Dを使用して別のプログラムに属するファイルをコンパイルしましたが、共通ファイルからログを記録したい場合はどうすればよいですか? プログラムAにいつ使用するのか、プログラムBにいつ使用するのかわからないため、何も定義できません。

4

3 に答える 3

1

グローバル変数を追加できます

const int iamprogram = ...;

差し迫った問題を解決するために、PROGRAM_AプログラムAとプログラムBにあるように定義されています。PROGRAM_Bこの変数に、ログを記録するファイルを直接含めることもできます。

const char *program_logfile = "/path/to/logfileA";

長期的には、共通コードがどのプログラムの一部であるかに依存しないように、コードをリファクタリングすることをお勧めします。これは、コードを 3 番目のプログラムにも使用したい場合に、はるかに維持しやすく拡張しやすいものです。

于 2015-12-03T10:32:06.180 に答える
1

プログラム固有の出力を取得するためのコールバックを実装できます。2 つの利点があります。共通部分からアプリケーションへの依存関係がない (共通部分がインターフェイスを定義する) ことと、実行時とコンパイル時に区別できることです。これにより、コマンド ライン パラメーターまたはユーザーを介して出力を変更するなど、将来の開発のための余裕が生まれます。交流。

次の例では、共通コード部分を「ライブラリ」と呼びます。

ライブラリ.h

typedef void (*logFunc_t)( logBuffer_t );
void setLogOutput( logFunc_t applicationLog );

library.c

logFunc_t logger; // might be good idea to initialize to an empty function, but omitted here

void setLogOutput( logFunc_t applicationLog )
{
  logger = applicationLog;
}

void log( logBuffer_t data )
{
  logger( data );
}

アプリケーション.cpp / アプリケーション.c

// here you should have the extern "C" in C++ application to ensure linkage compatibility
// I am assuming your shared code is C
extern "C" void myLogger( logBuffer_t data );

int main( int argc, char* agv[] )
{
  setLogOutput( &myLogger );
  // ...do your thing
  return 0;
}

void myLogger( logBuffer_t data )
{
  // ...log wherever
}
于 2015-12-03T11:48:29.557 に答える
0

実行時の動的リンクがこれを処理できるかどうかは 100% わかりません。ヘルパー関数を各実行可能ファイルに静的にリンクすると、確実に機能します。

両方のプログラムで同じ API を使用してロギング機能を提供します。何かをログに記録したいライブラリ関数にこの関数を呼び出してもらいます。ライブラリを使用しているプログラムによって提供される実装を取得します。

各プログラム、ライブラリごとにインクルードされるヘッダファイル

// common_log.h
#ifdef __cplusplus
extern "C"  // for the following definition only, no opening {
#endif

// used by code that can be part of either program
void common_log(char *msg, int log_prio);

tty C++ プログラムでの実装 (単純なロギング):

#include "common_log.h"
#include <iostream>

// used by the rest of the C++ program
void simple_logger(char *msg) {
    cerr << msg;
}

extern "C" void common_log(char *msg, int log_prio) {
    simple_logger(msg);
}

デーモン C プログラムでの実装:

#include "common_log.h"
#include <stdio.h>
#include <errno.h>

static FILE *logfp;
static int log_level;

// used by daemon code
void fancy_logger(char *msg, int log_prio) {
    if (log_prio < log_level)
        return;
    if (EOF == fputs(logfp, msg)) {
        perror("failed to write log message to log file: ");
    }
}

// or use linker tricks to make common_log an alias for fancy_log,
// if they both have the same signature and you don't need to do anything in the wrapper.

//extern "C"   // this is already C
void common_log(char *msg, int log_prio) {
    fancy_logger(msg, log_prio);
}

これには、リンカーが、リンクされているプログラムのシンボルを使用して、ライブラリ内の未定義のシンボルを解決できる必要があります。ライブラリがグローバル変数の弱い定義を提供するのと同様に機能すると思うので、メインプログラムの定義が優先されます。


simple_loggerが同じ署名を持っていても問題ない場合extern "C"は、それらに同じ名前を付けて、バウンス機能を回避できます。または、共通関数がいずれかのプログラムのプログラム独自のログ関数のエイリアスである可能性がある場合、単一の命令にコンパイルするのではなく、実際にそれを行うリンカーのトリックがあると思いますjmp(末尾呼び出しの最適化)。

于 2015-12-03T14:28:49.653 に答える