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