文字配列があるとしましょう:
#define LEN 10
char arr[LEN + 1];
それに対していくつかのscanf操作を実行しましょう:
scanf("Name: %s", arr);
誰かが10文字を超える名前を入力している場合、これは危険な場合があります。だからこれをよりよく使う:
scanf("Name: %10s", arr);
さて、LEN
を変更すると、問題が発生します。 arr
のコンテキストで10
を使用したすべての行を修正するには、コード全体を調べる必要があります。だから私はこのような何かについて考えました:
scanf("Name: %LENs", arr);
ただし、これは機能しません。LEN
は文字列内で使用されるため、プリプロセッサによって解決されません。
フォーマット文字列内で定義を使用する方法は?
Cは隣接する文字列リテラルを結合し、プリプロセッサパラメータを_#
_で文字列化できるため、次の方法でうまくいくはずです。
_#define LEN 10
// this converts to string
#define STR_(X) #X
// this makes sure the argument is expanded before converting to string
#define STR(X) STR_(X)
[...]
scanf("Name: %" STR(LEN) "s", arr);
_
マクロが必要なのは、_#LEN
_だけでは、LEN
が10に展開され、引数に_#
_を適用するマクロが1つだけの場合、結果は_"LEN"
_(引数は展開されません)。
プリプロセッサ/コンパイラは、次の手順でこれを変換します。
_1. scanf("Name: %" STR_(10) "s", arr);
2. scanf("Name: %" "10" "s", arr);
3. scanf("Name: %10s", arr);
_
最後のステップでは、文字列リテラルが1つに結合されます。
ちなみに、scanf()
形式の文字列では、ユーザーは文字通り入力する必要があります。
_Name: xyz
_
実際に一致します。これがあなたが望んでいたことではないかと思います。あなたはおそらくこのようなものが欲しいでしょう:
_fputs("Name: ", stdout);
fflush(stdout);
scanf("%" STR(LEN) "s", arr);
_
また、scanf()
をまったく使用しないことを検討してください。例: fgets()
、このプリプロセッサの魔法全体は廃止されました。 scanf()
を使用すべきでない理由については、私の scanf()
から離れた初心者向けガイドを参照してください。