web-dev-qa-db-ja.com

Scanf / Printf double変数C

Cに次のようなコードがあるとしましょう。

double var;
scanf("%lf", &var);
printf("%lf", var);
printf("%f", var);

Stdin変数「var」から読み取り、stdout「var」に2回出力します。私はそれがstdinからdouble変数を読み取る方法だと理解していますが、私の質問は次のとおりです:

  1. なぜ%lfでdoubleを印刷できるのですか?
  2. なぜ%fでdoubleを印刷できるのですか?
  3. どちらを使用するのが適切で正しいですか?
32
Dragos Rizescu

printfscanfなどの変数引数関数の場合、引数は昇格されます。たとえば、より小さい整数型はintに昇格され、floatdoubleに昇格されます。

scanfはポインターのパラメーターを受け取るため、プロモーションルールは有効になりません。 %fにはfloat*を、%lfにはdouble*を使用する必要があります。

printffloat引数を参照することはありません。floatは常にdoubleに昇格されます。形式指定子は%fです。しかし、C99は%lfprintf%fと同じだとも言っています。

C99§7.19.6.1fprintf関数

l(ell)次のdioux、またはX変換指定子がlong intまたはunsigned long int引数に適用されることを指定します。次のn変換指定子がlong int引数へのポインターに適用されること。次のc変換指定子がwint_t引数に適用されること。次のs変換指定子がwchar_t引数へのポインターに適用されること。またはは、後続のaAeEfFg、またはG変換指定子には影響しません。

38
Yu Hao

floatprintfに渡されると、自動的にdoubleに変換されます。これはデフォルト引数プロモーションの一部であり、これは主に歴史的な理由で、可変パラメーターリスト(...を含む)を持つ関数に適用されます。したがって、float%fの「自然な」指定子は、double引数で動作する必要があります。したがって、printf%fおよび%lf指定子は同じです。両方ともdouble値を取ります。

scanfが呼び出されると、直接値ではなくポインターが渡されます。 floatへのポインターはdoubleへのポインターに変換されません(ポインタータイプを変更しても、ポイント先のオブジェクトは変更できないため、これは機能しませんでした)。したがって、scanfの場合、%fの引数はfloatへのポインターでなければならず、%lfの引数はdoubleへのポインターでなければなりません。

9

マニュアルページを読む限り、scanfは、長さ修飾子 'l'が(浮動小数点の場合)引数がfloat型ではなくdouble型であることを示すため、 'lf、le、lg'を使用できると述べています。

印刷に関しては、公式には、マニュアルでは「l」は整数型にのみ適用されると書かれています。そのため、一部のシステムまたは一部の標準ではサポートされていない場合があります。たとえば、gcc -Wall -Wextra -pedanticでコンパイルすると、次のエラーメッセージが表示されます

a.c:6:1: warning: ISO C90 does not support the ‘%lf’ gnu_printf format [-Wformat=]

そのため、標準が構文をサポートしているかどうかを再確認することをお勧めします。

結論として、「%lf」で読み、「%f」で印刷するとします。

6
Artem Shinkarov