5

Linuxにはこの素晴らしい機能がありますdprintf

関数dprintf()and vdprintf()(glibc2 ライブラリにある) はfprintf()and とまったく同じvfprintf()ですが、指定されたストリームではなくファイル記述子 fd に出力する点が異なります。

ただし、同じソースが指摘しているように:

これらの関数は GNU 拡張機能であり、C や POSIX のものではありません。明らかに、名前の選択は不適切でした。多くのシステム (MacOS など) には、 と呼ばれる互換性のない関数がありdprintf()、通常は のデバッグ バージョンでprintf()、おそらく次のようなプロトタイプがあります。

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

ここで、最初のパラメーターはデバッグ レベルです (出力は tostderrです)。さらに、dprintf()(or DPRINTF) もデバッグ用の一般的なマクロ名ですprintf。したがって、おそらく、移植性を意図したプログラムではこの関数を避ける方がよいでしょう。

私の質問

必要な関数が存在する場合はそれを安全に呼び出すdprintfか、その関数が存在しない場合は合理的なエラーメッセージでコンパイルに失敗するセットアップを作成するにはどうすればよいですか? 私はこのようなことをすると思います:

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

SOMETHINGしかし、どうあるべきかわかりません。Linux だけに制限することはできると思いますが、もっと緩くすることはできますか?

4

3 に答える 3

9

dprintf()実際にはPOSIX.1-2008にあるように見えます(必要なセマンティクスを使用)ので、これを行うことができます:

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

__GLIBC__gnuビルドシステムを使用している場合に定義されます。これはおそらく、小さなテストプログラムを作成せずにできる限り安全です。

于 2010-01-22T00:15:26.090 に答える
4

ビルドシステムに 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*もちろん、出力先のファイル記述子がわかっている場合は、代わりにポインターをそのままにしておいてください。

于 2010-01-21T23:53:43.337 に答える
2

Autoconf テストではdprintf(1, "blablabla")、書き込みが stdout か stderr かdprintf(-1, "blablabla")、興味深い方法で失敗するか stderr に書き込むかをチェックできます。

libc が間違った を提供する場合は、それを自分で(またはそれ以上に) およびdprintf()の上に実装することができます。そして、あなたの 'dprintf.o' をリンカにメンションして、libc よりもあなたのものを優先させます。snprintf()asprintf()write()

より良い名前が必要な場合は、 を提案しfdprintf()ます。

于 2010-01-21T23:46:46.163 に答える