У меня есть проект, в котором мне нужно различать файлы, принадлежащие демону linux (написанному на C) и простой программе на Linux (написанной на C ++). Эти два проекта использовали 2 общих файла (helpers_functions). Демон и программа имеют разную систему регистрации. Запись демона в файл, программа в стандартный вывод.
Проблема возникает, когда я хочу записать что-то в общих функциях для обеих программ (внутри файла helper_functions). Я не хочу передавать через параметр, что это программа A или программа B.
У меня компиляция файлов принадлежит отдельным программам с флагом g ++ -D, но что я могу сделать, когда я хочу войти из общих файлов? Я не могу ничего там определить, потому что я не знаю, когда я использую это для программы A, или когда для программы B.
Вы можете добавить глобальную переменную
const int iamprogram = ...;
который определен как PROGRAM_A
в программе А и PROGRAM_B
в программе B, чтобы решить насущную проблему. Вы также можете сделать эту переменную напрямую содержащей файл, в который вы хотите войти:
const char *program_logfile = "/path/to/logfileA";
В долгосрочной перспективе я предлагаю вам реорганизовать свой код так, чтобы общий код не зависел от того, в какую программу он входит. Это гораздо удобнее в обслуживании и расширении для случая, когда вы хотите использовать код и для третьей программы.
Вы можете реализовать обратный вызов для получения выходных данных программы. Есть два преимущества: нет зависимости от общей части для приложения (общая часть определяет интерфейс), и вы можете провести различие во время выполнения и во время компиляции, что дает больше места для будущей разработки, такой как изменение вывода с помощью параметров командной строки или пользователя взаимодействие.
В следующем примере давайте обратимся к общей части кода как «библиотека».
library.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 );
}
application.cpp / application.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
}
Я не уверен на 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);
#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);
}
#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
инструкция (оптимизация остаточного вызова).