7

0 の scanf 幅指定子を使用するには?
1) 無制限の幅 (cywin gcc バージョン 4.5.3 で見られるように)
2) UB
3) 何か他のもの?

私のアプリケーション (表示されていません) は、scanf() のより大きなフォーマット文字列の一部として幅指定子を動的に形成します。"%0s"フォーマット文字列の途中にが作成されることはほとんどありません。このコンテキストでは、宛先文字列にはを格納する%0sためのスペースが 1 バイトしかなく、上記の動作 #1 で問題が発生します。scanf()\0

注: 次のテスト ケースでは、定数形式を使用します。

#include <memory.h>
#include <stdio.h>

void scanf_test(const char *Src, const char *Format) {
  char Dest[10];
  int NumFields;
  memset(Dest, '\0', sizeof(Dest)-1);
  NumFields = sscanf(Src, Format, Dest);
  printf("scanf:%d Src:'%s' Format:'%s' Dest:'%s'\n", NumFields, Src, Format, Dest);
}

int main(int argc, char *argv[]) {
  scanf_test("1234" , "%s");
  scanf_test("1234" , "%2s");
  scanf_test("1234" , "%1s");
  scanf_test("1234" , "%0s");
  return 0;
}

出力:

scanf:1 Src:'1234' Format:'%s' Dest:'1234'  
scanf:1 Src:'1234' Format:'%2s' Dest:'12'  
scanf:1 Src:'1234' Format:'%1s' Dest:'1'  
scanf:1 Src:'1234' Format:'%0s' Dest:'1234' 

私の質問は最後の行についてです。幅が 0 の場合、幅が 0 になるのではなく、幅が制限されないようです。これが正しい動作または UB である場合、別の方法で幅が 0 の状況にアプローチする必要がありますか、または他の scanf() 形式を考慮する必要がありますか?

4

2 に答える 2

10

最大フィールド幅指定子はゼロ以外でなければなりません。C99、7.19.6.2:

フォーマットは、初期シフト状態で開始および終了するマルチバイト文字シーケンスでなければなりません。フォーマットはゼロ以上のディレクティブで構成されます: 1 つ以上の空白文字、通常のマルチバイト文字 (空白文字でも%ない)、または変換仕様。各変換仕様は、文字によって導入されます%。の後に%、次の文字が順番に表示されます。
— オプションの代入抑制文字*
最大フィールド幅 (文字数) を指定するオプションのゼロ以外の 10 進整数。—受信オブジェクトのサイズを指定
するオプションの長さ修飾子。
変換指定子適用する変換のタイプを指定する文字。

したがって、 を使用0した場合の動作は未定義です。

于 2013-05-29T16:44:12.033 に答える
4

これは、n1570.pdf (C11 標準ドラフト) の 7.21.6.2 からのものです。

% の後に、以下が順番に表示されます。

— オプションの割り当て抑制文字 *。

— 最大フィールド幅 (文字数) を指定するゼロより大きいオプションの 10 進整数。

...

C 標準では、最大フィールド幅は 0 より大きくなければならないことが規定されているため、これは未定義の動作です。

入力項目は、指定されたフィールド幅を超えない入力文字の最長シーケンスとして定義され、...

幅 0 のフィールドを読み取り、それを文字列 (空の文字列) として に割り当てることによって、何を達成したいDestですか? どの実際の問題を解決しようとしていますか? like を割り当てるだけの方が明確に思えます*Dest = '\0';

于 2013-05-29T16:44:43.357 に答える