5

Linux 有这个不错的功能dprintf

函数dprintf()and vdprintf()(在 glibc2 库中找到)与 and 完全类似fprintf()vfprintf()除了它们输出到文件描述符 fd 而不是给定流。

但是,正如同一来源指出的那样:

这些函数是 GNU 扩展,而不是 C 或 POSIX。显然,名字选错了。许多系统(如 MacOS)具有不兼容的函数dprintf(),通常称为 的调试版本printf(),可能带有类似

void dprintf (int level, const char *format, ...);

其中第一个参数是调试级别(输出为 to stderr)。此外,dprintf()(or DPRINTF) 也是一个流行的调试宏名称printf。因此,可能最好在旨在可移植的程序中避免使用此功能。

我的问题

如何进行设置以安全地调用dprintf我想要的(如果存在),或者如果该函数不存在,则无法编译并显示一些合理的错误消息?我想我会做这样的事情:

#ifdef SOMETHING
    #define Dprintf dprintf
#else
    #error "no dprintf"
#endif

但我不知道SOMETHING应该是什么。我想我可以将它限制在 Linux 上,但我可以让它更宽松吗?

4

3 回答 3

9

看起来dprintf()实际上是在POSIX.1-2008中(使用你想要的语义),所以你可以这样做:

#if !defined(__GLIBC__) && _POSIX_C_SOURCE < 200809
#error "dprintf may not exist, or may be wrong"
#endif

__GLIBC__如果您使用的是 gnu 构建系统,则定义。在不编写小型测试程序的情况下,这可能是尽可能安全的。

于 2010-01-22T00:15:26.090 回答
4

如果您在构建系统中使用自动工具,则可以进行 autoconf 测试。

AC_LANG([C])
AC_USE_SYSTEM_EXTENSIONS
AC_ARG_WITH([dprintf],
  [AS_HELP_STRING([--with-dprintf],
    [Assume that dprintf prints to a specified file descriptor])],
  [], [with_dprintf=check])
AS_IF([test "x$with_dprintf" = xcheck],
  [AC_RUN_IFELSE(
    [AC_LANG_PROGRAM([[
        #include <stdio.h>
        #include <string.h>
        int debug_level;
      ]], [[
        char msg[] = "Hello, world!\n";
        char rcv[sizeof(msg)] = "";
        FILE *f = tmpfile();
        int fd = fileno(f);
        debug_level = fd - 1;
        dprintf(fd, "%s", msg);
        fseek(f, 0, SEEK_SET);
        fread(rcv, 1, sizeof(msg), f);
        return strcmp(msg, rcv);
      ]]
    )], [with_dprintf=yes])])
AS_IF([test "x$with_dprintf" = xyes],
  [AC_DEFINE([HAVE_DPRINTF], [1],
    [dprintf prints to a specified file descriptor])])

(允许--with-dprintf--without-dprintf在交叉编译时,因为AC_RUN_IFELSE在这些情况下无效。)


fdopen不在标准 C 中,但POSIX.2 及更高版本中。我不记得任何没有它的类 UNIX —— 哎呀,甚至 Windows 都有它。

int fdprintf(int fd, char *fmt, ...) {
    va_list ap;
    FILE *f = fdopen(fd);
    int rc;

    va_start(ap, &fmt);
    rc = vfprintf(f, fmt, ap);
    fclose(f);
    va_end(ap);
    return rc;
}

当然,如果您知道要打印到哪个文件描述符,只需保留FILE*指针即可。

于 2010-01-21T23:53:43.337 回答
2

Autoconf 测试可以检查是否dprintf(1, "blablabla")写入 stdout 或 stderr,以及是否dprintf(-1, "blablabla")以有趣的方式失败或写入 stderr。

如果 libc 给你错误dprintf(),你可以自己在snprintf()(甚至更好asprintf())和write(). 然后向链接器提及您的“dprintf.o”,以便它更喜欢您的而不是 libc。

如果你想要一个更好的名字,我建议fdprintf()

于 2010-01-21T23:46:46.163 回答