dprintf的跨平台兼容性

时间:2010-01-21 22:45:41

标签: c linux posix conditional-compilation

Linux有这个很好的功能dprintf

  

函数dprintf()vdprintf()(在glibc2库中找到)是fprintf()vfprintf()的精确类似物,不同之处在于它们输出到文件描述符fd而不是对于给定的流。

然而,正如同一消息来源指出的那样:

  

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

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

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

我的问题

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

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

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

4 个答案:

答案 0 :(得分:9)

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

#if !defined(__GLIBC__) && _POSIX_C_SOURCE < 200809
#error "dprintf may not exist, or may be wrong"
#endif
如果您使用的是gnu构建系统,则会定义

__GLIBC__。如果不编写小型测试程序,这可能就像你一样安全。

答案 1 :(得分: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*指针。

答案 2 :(得分:2)

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

如果libc向您提供了错误的dprintf(),您可以在snprintf()(或更好asprintf())和write()之上自行实施。{p>然后向链接器提及你的'dprintf.o',这样它就更喜欢你的libc了。

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

答案 3 :(得分:0)

与dmcer的答案相关,这里有一个类似问题的link