Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何允许C库使用调用者&x27;什么是日志记录?_C_Logging - Fatal编程技术网

如何允许C库使用调用者&x27;什么是日志记录?

如何允许C库使用调用者&x27;什么是日志记录?,c,logging,C,Logging,这对于Linux库来说意味着“允许应用程序将libs日志挂接到它的日志设施中。”这通常是通过什么机制实现的?使用指向日志函数的指针的函数?您可以显示示例吗?例如,在库的配置中,您可以有一个用户定义的函数指针: struct my_lib_config { void (* log) (const char * message); }; 在合理违约的情况下: void log_default (const char * message) { fprintf (stderr, "%s

这对于Linux库来说意味着“允许应用程序将libs日志挂接到它的日志设施中。”这通常是通过什么机制实现的?使用指向日志函数的指针的函数?您可以显示示例吗?

例如,在库的配置中,您可以有一个用户定义的函数指针:

struct my_lib_config
{
    void (* log) (const char * message);
};
在合理违约的情况下:

void log_default (const char * message)
{
    fprintf (stderr, "%s\n", message);
}

if (!config.log)
    config.log = log_default;

使用此选项,您的库将默认登录到stderr,除非应用程序将
log
函数指针设置为它们自己的函数。

以下是来自SQLite的示例。您可以通过使用参数调用来设置它的日志记录方式。传入一个函数指针和一个空指针。函数指针有三个参数;空指针、整数和字符*。当SQLite需要记录某些内容时,它会调用函数指针,传入传递给
CONFIG\u log
的无效指针、结果代码和包含日志消息的字符串

SQLITE_配置_日志

SQLITE_CONFIG_LOG选项接受两个参数:指向调用签名为
void(*)(void*,int,const char*)
的函数的指针,以及指向void的指针。如果函数指针不为NULL,则sqlite3_log()将调用它来处理每个日志事件。如果函数指针为NULL,sqlite3_log()接口将变为no-op。无论何时调用SQLITE_CONFIG_log函数,作为SQLITE_CONFIG_log的第二个参数的void指针将作为第一个参数传递给应用程序定义的记录器函数。logger函数的第二个参数是对应sqlite3_log()调用的第一个参数的副本,旨在作为结果代码或扩展结果代码。传递给记录器的第三个参数是通过sqlite3\u snprintf()格式化后的日志消息。SQLite日志记录接口不可重入;应用程序提供的记录器函数不得调用任何SQLite接口。在多线程应用程序中,应用程序定义的记录器函数必须是线程安全的

您可以在中看到
sqlite3\u log()
的实际实现。它使用
snprintf()

/*
** This is the routine that actually formats the sqlite3_log() message.
** We house it in a separate routine from sqlite3_log() to avoid using
** stack space on small-stack systems when logging is disabled.
**
** sqlite3_log() must render into a static buffer.  It cannot dynamically
** allocate memory because it might be called while the memory allocator
** mutex is held.
*/
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
  StrAccum acc;                          /* String accumulator */
  char zMsg[SQLITE_PRINT_BUF_SIZE*3];    /* Complete log message */

  sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
  acc.useMalloc = 0;
  sqlite3VXPrintf(&acc, 0, zFormat, ap);
  sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
                           sqlite3StrAccumFinish(&acc));
}

/*
** Format and write a message to the log if logging is enabled.
*/
void sqlite3_log(int iErrCode, const char *zFormat, ...){
  va_list ap;                             /* Vararg list */
  if( sqlite3GlobalConfig.xLog ){
    va_start(ap, zFormat);
    renderLogMsg(iErrCode, zFormat, ap);
    va_end(ap);
  }
}

或者你可以看看。默认情况下,它会将错误记录到stderr,但您可以提供自己的回调来覆盖它。调用
png\u set\u error\u fn()
,传递
png\u struct
、一个空指针和两个回调,一个用于错误,一个用于警告。然后它将使用两个参数调用函数指针;
png\u结构
,通过该结构,您可以使用
png\u get\u error\u ptr()和
char*
访问空指针。同样,libpng处理
snprintf()
,只向日志回调传递一个
char*

似乎有了这个函数签名,我就可以在堆栈上的静态缓冲区中进行大量snprintf打印了……好吧,请随意使用printf样式。我只是想让这个例子简单一些。是的,我对简单性不太感兴趣,我更感兴趣的是它通常是如何完成的。