dprintf的跨平台兼容性

发布于 2024-08-18 16:58:40 字数 1024 浏览 6 评论 0原文

Linux 有一个很好的函数 dprintf

函数 dprintf()vdprintf()(在 glibc2 库中找到)与 fprintf() 和 < code>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,但我可以让它更宽松吗?

Linux has this nice function dprintf:

The functions dprintf() and vdprintf() (as found in the glibc2 library) are exact analogues of fprintf() and vfprintf(), except that they output to a file descriptor fd instead of to a given stream.

however as that same source points out:

These functions are GNU extensions, not in C or POSIX. Clearly, the names were badly chosen. Many systems (like MacOS) have incompatible functions called dprintf(), usually some debugging version of printf(), perhaps with a prototype like

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

where the first parameter is a debugging level (and output is to stderr). Moreover, dprintf() (or DPRINTF) is also a popular macro name for a debugging printf. So, probably, it is better to avoid this function in programs intended to be portable.

My question

How can I make a setup that will safely call the dprintf that I want, if it exists, or fail to compile with some reasonably sane error message if that function doesn't exist? I guess I'd do something like this:

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

but I don't know what SOMETHING should be. I guess I could restrict it to just Linux but could I make it looser?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半城柳色半声笛 2024-08-25 16:58:40

看起来 dprintf() 实际上在 POSIX.1- 2008 (具有您想要的语义),因此您可以执行以下操作:

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

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

Looks like dprintf() is actually in POSIX.1-2008 (with the semantics you want), so you can do this:

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

__GLIBC__ is defined if you're using a gnu build system. This is probably as safe as you can be without writing a small test program.

煮酒 2024-08-25 16:58:40

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

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 语言,但是< /em> 在 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* 指针即可。

You could make an autoconf test, if you're using autotools for your buildsystem.

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])])

(Allowing for --with-dprintf or --without-dprintf when cross-compiling, as AC_RUN_IFELSE isn't valid in those cases.)


fdopen isn't in standard C, but it is in POSIX.2 and later. I don't recall any UNIX-like that doesn't have it -- heck, even Windows has it.

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;
}

Of course, if you know which file descriptor you'll be printing to, just keep the FILE* pointer around instead.

暗喜 2024-08-25 16:58:40

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

如果 libc 给出了错误的 dprintf(),您可以在 snprintf() 之上自己实现它(或者更好的 asprintf()) ) 和 write()。然后向链接器提及你的“dprintf.o”,这样它就更喜欢你的而不是 libc 的。

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

An Autoconf test could check whether dprintf(1, "blablabla") writes to stdout or stderr, and whether dprintf(-1, "blablabla") fails in an interesting way or writes to stderr.

If libc gives you with the wrong dprintf(), you could implement it yourself on top of snprintf() (or even better asprintf()) and write(). And then mention your 'dprintf.o' to the linker so it prefers yours to libc's.

If you want a better name, I propose fdprintf().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文