[英]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.