Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C dprintf的跨平台兼容性_C_Linux_Posix_Conditional Compilation - Fatal编程技术网

C dprintf的跨平台兼容性

C dprintf的跨平台兼容性,c,linux,posix,conditional-compilation,C,Linux,Posix,Conditional Compilation,Linux有一个很好的功能: 函数dprintf()和vdprintf()(可以在glibc2库中找到)与fprintf()和vfprintf()完全类似,只是它们输出到文件描述符fd而不是给定流 然而,正如该消息来源指出的那样: 这些函数是GNU扩展,而不是在C或POSIX中。显然,这些名字选得不好。许多系统(如MacOS)具有名为dprintf()的不兼容函数,通常是printf()的某个调试版本,可能有类似的原型 其中第一个参数是调试级别(输出到stderr)。此外,dprintf()(或

Linux有一个很好的功能:

函数
dprintf()
vdprintf()
(可以在glibc2库中找到)与
fprintf()
vfprintf()
完全类似,只是它们输出到文件描述符fd而不是给定流

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

这些函数是GNU扩展,而不是在C或POSIX中。显然,这些名字选得不好。许多系统(如MacOS)具有名为
dprintf()
的不兼容函数,通常是
printf()的某个调试版本
,可能有类似的原型

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

我的问题 我如何设置安全地调用我想要的
dprintf
,如果该函数存在,或者如果该函数不存在,则无法编译并显示合理的错误消息?我想我会这样做:

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

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

自动功能测试可以检查
dprintf(1,“blablablabla”)
是否写入stdout或stderr,以及
dprintf(-1,“blablabla”)
是否以有趣的方式失败或写入stderr

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


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

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])])
当然,如果您知道要打印到哪个文件描述符,只需保留
文件*
指针即可。

看起来像
dprintf()
实际在中(具有您想要的语义),因此您可以执行以下操作:

#if !defined(__GLIBC__) && _POSIX_C_SOURCE < 200809
#error "dprintf may not exist, or may be wrong"
#endif
#如果!定义的(uuu GLIBC_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
#错误“dprintf可能不存在,或可能错误”
#恩迪夫

如果您使用的是gnu构建系统,则会定义
\uuu GLIBC\uuu
。无需编写小型测试程序,这可能是最安全的方法。

+1(尽管我没有使用autoconf或任何相关配置)——我使用dprintf代替asprintf+write,因为它在错误处理程序中使用,我不想担心堆的工作。@BCS:您不需要使用堆,您的函数可以在堆栈上分配缓冲区(固定大小的缓冲区,或使用
alloca()
)@Hasturkun:fixed size不起作用(我没有合理的长度上限),在某些错误恢复情况下,堆栈空间非常紧。在
snprintf
asprintf
之上实现它是个坏主意,因为这些要求字符串适合内存并具有故障案例。相反,使用
fdopen
,然后只使用
fprintf
@R:引用辛普森先生的话:“Duh!”。我没有构建系统(好的,我通过make-remaking-make-files使用make)顺便说一句,经常会看到
(_POSIX_-C_-SOURCE-0)<200809
,所以它仍然是有效的(错误)表达式,即使宏未定义或为空。但如果未定义某些内容,预处理器将用0替换它,因此
\u POSIX\u C\u SOURCE<200809
将扩展到
0<200809
,如果
\u POSIX\u C\u SOURCE
未定义或为0。对于空宏,您是对的。
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;
}
#if !defined(__GLIBC__) && _POSIX_C_SOURCE < 200809
#error "dprintf may not exist, or may be wrong"
#endif