15

さて、Windows 7 で MinGW (GCC 4.6.2) を使用して C ファイルをコンパイルすると、奇妙な問題が発生しました。問題のファイルには、次の C コードが含まれています。

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("%2hhX\n", 250);
    char c[80];
    snprintf(c, sizeof(c), "%2hhX", 250);
    printf("%s\n", c);
    return 0;
}

コンパイルは次のようになります。

$ gcc.exe -std=c99 -pedantic -Wall test.c
test.c: In function 'main':
test.c:6:2: warning: unknown conversion type character 'h' in format [-Wformat]
test.c:6:2: warning: too many arguments for format [-Wformat-extra-args]

さて、私にとって奇妙なのは、snprintf6行目の呼び出しについては文句を言うが、 printf4行目の呼び出しについては文句を言わないということです。何かが足りないのでしょうか、それとも警告が間違っているのでしょうか? また、おそらくフォーマット文字列に相当するものはあります"%2hhX"か? (char 変数を 16 進数値として出力しようとしています。)

4

2 に答える 2

21

歴史的に、特に C99 のサポートに関しては、MinGW は少し奇妙な状況にありました。MinGW は、主に Windows と共に配布される msvcrt.dll ランタイムに依存しており、そのランタイムは C99 をサポートしていません。

そのため、古いバージョンの MinGW では、C99 固有の書式指定子を使用すると、C99 モードで問題が発生する可能性があります。また、歴史的に、GCC は、msvcrt.dll が C99 指定子をサポートしていないことに対して、特別な対応をしていませんでした。-Wformatそのため、機能しないフォーマットについて警告しない状況に陥ります。

両方の面で状況が改善されています。GCC は、MS ランタイムで使用する場合、次のように -Wformat を特定してサポートしています。

  • -Wpedantic-ms-formatGCCが文句を言わないよう"I32""I64"(文書化されていますが、4.7.0でも認識されないという苦情が依然としてあります-おそらくそれは真新しいです)
  • するms_printfオプション__attribute__((__format__))

一方、MinGW は、MSVC のバリアントである がまったく異なる動作snprintf()をするため、しばらくの間独自のものを提供してきました。_snprintf()ただし、MinGW は長い間 msvcrt.dll に依存していたため、printf()C99 形式指定子は機能printf()しませんでした。ある時点で、MinGW はprintf()、適切な C99 (および GNU?) のサポートを取得できるように、独自のバージョンの と フレンドを提供し始めました。ただし、保守的な側にあるようで、最初は msvcrt.dll バージョンを置き換えませんでした。のような名前があり__mingw_printf()ます。

4.6.1 と 4.7.0 の間のある時点で、MinGW ヘッダーは MinGW が提供するバージョンを msvcrt.dll 関数の代わりとして使用し始めたようです (少なくとも C99 を指定した場合)。

ただし、新しいバージョンでは、GCC と MinGW はまだ同期していないようです。GCC が MinGW で実際に動作しない指定子について警告しないのと同様に、動作する指定子について不平を言うことはありません。

次のコード スニペットを試して、お使いのバージョンの MinGW がどの程度サポートされているかを確認してください"hhX"

printf("%hhX\n", 0x11223344);
__mingw_printf("%hhX\n", 0x11223344);

発生している問題を解決するために何を提案すればよいかわかりません-MinGWstdio.hヘッダーにパッチを適用__attribute__((__format__ (gnu_printf, ...)))して、printf関数の属性を持つようにすることができると思います(新しいstdio.h.そのため、GCC はフォーマット サポートのデフォルトの考え方を使用します)。

于 2012-05-21T06:49:54.583 に答える
4

他の回答に加えて、GCC での printf 形式のチェックに関する詳細情報を次に示します。

あなたが言うとき__attribute__((__format__ (FORMAT, ...)))、の値はFORMAT(printfに関する限り)次のいずれかです:printf、、。gnu_printfms_printf

ms_printf関数が Microsoft Visual Studio CRT の printf ファミリ関数用の書式文字列を受け取ると GCC に想定させます。zこれは、GCC が、hhおよびについて不平を言うことを意味しますが、警告なしllに通過します。I64

gnu_printfGCC は、その下に GNU libc printf 実装を想定します (または、POSIX/C99 準拠の printf 実装だけかもしれませんが、よくわかりません)。したがって、GCC は およびその他の Microsoft 拡張機能について不平を言いますが、 、およびI64を受け入れます。zhhll

printfは、ms_printfWindows 用にコンパイルする場合のエイリアスであり、gnu_printfそれ以外の場合のエイリアスです。

このチェックは、使用されている実際の printf 実装と完全に直交していることに注意してください。これは、独自の printf のような関数を作成して配置すると簡単に確認できます。GCC__attribute__((__format__ (FORMAT, ...)))は に応じてさまざまなことについて文句を言いFORMATますが、関数内でやりたいことは何でもできます。

私が知っている利用可能なprintf実装:

  • -D__USE_MINGW_ANSI_STDIO=1MinGW.org および MinGW-w64 ツールチェーンのMinGW ANSI STDIO (でコンパイル)。ms_printf(完全に?) および形式に準拠しgnu_printfます (部分的に - 位置引数をサポートしません)。
  • MSVCRT (なしでコンパイル-D__USE_MINGW_ANSI_STDIO=1)。準拠ms_printf(duh...)、準拠gnu_printfは非常に低く、ランタイム バージョンに依存します (古いバージョンはサポートしていませんでしたが、新しいバージョンはサポートしllています。これまでのところ、どのバージョンでもサポートされていません。ただし、GCC はこれらの開発を喜んで認識していません。 VC 6.0 時代の msvcrt は最悪のケースを想定しているようです)。zhh
  • gnulib。完全に(またはほぼ完全に)準拠していms_printfます。gnu_printf

MinGW.orgのstdio.hヘッダーは を使用しませんattribute format

stdio.hMinGW-w64のヘッダーはattribute format gnu_printf、MinGW ANSI STDIO 実装に使用しますが、MSVCRT 実装には何も使用しません。修正済み: MinGW-w64 ヘッダーの新しいバージョンでは、MSVCRT 実装stdio.hに使用されます。attribute format ms_printf

gnulib は と の違いを完全に認識しておりprintfgnu_printfいくつかの複雑なマクロに応じてどちらか一方を選択します (おそらく、フォーマットが示すことをサポートする適切な実装が付随しています)。

(現時点で) GCC フォーマット チェックに問題があることがわかっているソフトウェアの一部:

  • glib -printfフォーマットを使用しますが、実装は gnulib からです。に変更するための未解決のバグがありますgnu_printf
  • CPython - コードにはさまざまなz形式がありますが、公式のバイナリは MSVCRT に対してビルドされています。printf拡張機能もよく使用しますが、拡張ヘッダーにもフォーマットを使用しzます
于 2014-03-05T21:35:22.277 に答える