1. ホーム
  2. c++

[解決済み] なぜ printf("%f",0); は未定義の動作をするのですか?

2023-04-04 04:50:51

質問

文の内容

printf("%f\n",0.0f);

は0を表示します。

しかし、この文は

printf("%f\n",0);

はランダムな値を表示します。

何らかの未定義の動作を示していることは分かっているのですが、具体的な理由が分かりません。

すべてのビットが 0 である浮動小数点値は、まだ有効な float であり、値は 0 です。

float そして int は私のマシンでは同じサイズです (それが関連するかどうかは別として)。

で浮動小数点リテラルの代わりに整数リテラルを使用するのはなぜですか? printf で整数リテラルを使用すると、このような動作になるのでしょうか?

追伸:同じ動作は、私が使用する場合、見ることができます

int i = 0;
printf("%f\n", i);

どのように解決するのですか?

この "%f" 形式では、引数として double . 型の引数を与えています。 int . そのため、動作が未定義になっています。

規格は、all-bits-zeroが有効な表現であることを保証していません。 0.0 (の有効な表現であることを保証するものではなく、また、任意の double の値、あるいは intdouble は同じ大きさです(これは double ではなく float でない)、あるいは、たとえ同じサイズであっても、それらが同じ方法で変量関数に引数として渡されることです。

あなたのシステムで "work"することが起こるかもしれません。それは、エラーの診断を困難にするため、未定義の動作の最悪の症状です。

N1570 7.21.6.1項 9:

... もし,いずれかの引数が,対応する 変換指定に対して正しい型でない場合,その動作は未定義である。

型の引数 floatdouble に昇格し、そのため printf("%f\n",0.0f) は動作します。よりも狭い整数の型の引数は int に昇格します。 int または unsigned int . これらのプロモーション・ルール(N1570 6.5.2.2 paragraph 6で規定)は、以下の場合には役に立ちません。 printf("%f\n", 0) .

もし、定数 0 を期待する非変数関数に渡すと double の引数を期待する非変数型関数の場合、関数のプロトタイプが見えると仮定すると、動作はよく定義されています。例えば sqrt(0) (の後に #include <math.h> の後) は、暗黙のうちに引数 0 から int から double -- の宣言から、コンパイラは sqrt を期待していることがわかるからです。 double 引数を期待することを示します。に対してはそのような情報はありません。 printf . のような可変個体関数は printf のような変数は特殊で、呼び出しを記述する際にはより注意が必要です。