2

我有一个项目,我需要区分文件属于 linux 守护进程(用 C 编写)和简单的 linux 程序(用 C++ 编写)。这两个项目使用了 2 个共享文件(helpers_functions)。守护进程和程序有不同的日志系统。守护进程写入文件,程序写入标准输出。

当我想在两个程序的通用函数中记录某些内容时(在 helper_functions 文件中),就会出现问题。我不想通过参数传递,这是程序 A 或程序 B。

我已经编译了属于带有 g++ 标志-D的单独程序的文件,但是当我想从公共文件中登录时,我该怎么办?我无法在那里定义任何东西,因为我不知道何时将它用于程序 A,或何时用于程序 B。

4

3 回答 3

1

您可以实现回调以获取程序特定的输出。有两个好处:公共部分与应用程序之间没有依赖关系(公共部分定义了接口),并且您可以在运行时与编译时进行区分,这为未来的开发提供了更多的空间,例如通过命令行参数或用户更改输出相互作用。

在以下示例中,我们将公共代码部分称为“库”。

图书馆.h

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

图书馆.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 回答
1

您可以添加一个全局变量

const int iamprogram = ...;

它被定义PROGRAM_A在程序 A 和PROGRAM_B程序 B 中,以解决眼前的问题。您还可以使此变量直接包含您要登录到的文件:

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

从长远来看,我建议你重构你的代码,使公共代码不依赖于它属于哪个程序。对于您还想将代码用于第三个程序的情况,这更具可维护性和可扩展性。

于 2015-12-03T10:32:06.180 回答
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 回答