繁体   English   中英

dprintf的跨平台兼容性

[英]Cross-platform compatibility of dprintf

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但我可以让它更宽松吗?

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

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

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

如果您正在为构建系统使用autotools,则可以进行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*指针即可。

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

如果libc给你错误的dprintf() ,你可以在snprintf() (甚至更好的asprintf() )和write()之上自己实现它。 然后向链接器提及你的'dprintf.o',这样它就更喜欢你的libc了。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM