5

重複の可能性:
警告:フォーマットは文字列リテラルではなく、フォーマット引数もありません

char[] s = "hi"; printf(s)非常に簡単な質問があります。「警告:フォーマットは文字列リテラルではなく、フォーマット引数もありません」という警告を発行するのに、なぜ発行しないのですprintf("aa")か。

char配列と文字列リテラルの違い(1つはともう1つconst char const*char*)をすでに読みましたが、printf()署名から:

http://www.gnu.org/software/libc/manual/html_node/Formatted-Output-Functions.html#Formatted-Output-Functions

私はそれがそのタイプのどれにも適していると思います。だから私の質問は、なぜprintf("aaa")警告を出さないのですか(リテラルが定数であるのに対し、配列はそうではないことをどういうわけかチェックしますか?)

4

4 に答える 4

6

最近のGNUコンパイラや他の多くのコンパイラは、実際に、printf提供された引数に対して-familyのフォーマット文字列をチェックします。コンパイラは、リテラル以外の文字列に対してこれを実行できないことを警告しています。

非リテラル形式の文字列を使用することは悪い習慣と見なされます。制御できないフォーマット文字列を使用することは、はるかに悪いことです。

于 2012-07-10T15:08:40.437 に答える
4

この理由は、約10〜15年前に、「s」がユーザーから入力されたprintf(s)を安全に呼び出すことができると人々が考えていたために、多くのセキュリティ問題が発生したためです。多くのコンパイラは、問題を回避するためにこれに対する警告を追加しました。文字列を出力するだけの場合は、代わりにputs()を使用してください。printfに送信する文字列に「%」文字が含まれていないことが完全にわからない場合は、printf( "%s"、s);を使用する必要があります。

于 2012-07-10T15:11:11.017 に答える
1

2番目のケースでは、コンパイラは文字列にフォーマットが含まれていないことを認識しているので、危険ではないと思います。

/* "aa" is not dangerous, so do not display a warning */
printf("aa")

最初のケースでは、コンパイラはフォーマット文字列の値を認識できない可能性があるため、検証できません。

/* the compiler doesn't know the content of the memory region pointed by `s`, so
   he can't determine if it's dangerous or not. Then display a warning */
printf(s)
于 2012-07-10T15:07:52.500 に答える
1

免責事項:これが警告理由であるかどうかはわかりませんが、それは理由です。

の引数prinrfの数は変換指定子の数に依存するため、文字列リテラルをフォーマット文字列として使用しないことは非常にまれです(つまり、エラーの可能性があります)。さらに、フォーマット文字列がリテラルでない場合は、他の場所(たとえば、ユーザーまたはファイル入力)から取得されます。この場合、誤った(または悪意のある)入力によってプログラムがクラッシュしたり、さらに悪いことに、コードが挿入されたりする可能性があります(つまり、セキュリティ上の欠陥)。

いずれにせよ、リテラルではなく、フォーマット引数を持たないものを印刷したい場合は、とにかくputsではなく、を探している可能性がありprintfます。(putsIMHOは、Cライブラリで最も使用されていない関数です。これを使用する「hello、world」を見たことがありますか?)

于 2012-07-10T15:10:59.513 に答える