2017-04-03 16 views
0

変数宣言の特定のケースには既に回答している質問がありますが、他のリテラル定数の使用についてはどうでしょうか?例えば標準Cではリテラルサフィックスが必要ですか?

uint64_t a; 
... 
int32_t b = a/1000000000; 

は、任意の標準Cコンパイラの次のいずれかにコードと同等の最後のピースはありますか?言い換えれば

uint64_t a; 
... 
int32_t b = (int32_t)(a/UINT64_C(1000000000)); 

、(我々は暗黙の1が間違っている場合には明示的なキャストを使用している想定)すべてで必要xINTn_Cマクロですか?

EDIT

コンパイラは1000000000を読み取ると、それが解決するまで(すべてのオーバーフロービットを落とす)内部表現にintとして格納するか、(長い長い)ことがで可能な限り最高の精度を格納する必要が許可されています全体の表現型?それは実装定義の動作ですか、それとも標準によって義務付けられていますか?

+0

質問を編集して既存の回答のポイントを無効にすることは好ましくありません。 –

+0

また、「ジェネリックC」やC11規格ではなく、古いC99規格についてなぜ尋ねるのが不思議です。確かに、 ''と ''はC90には含まれていませんでしたが、C99はかなり古いものです。 –

+0

@JonathanLeffler私は編集の問題を修正しました。私はANSI Cの後で最も広くサポートされている標準であり、私が使用しているものなので、C99について尋ねています。すべてのコンパイラがC11をサポートしていれば、世界はより良くなりますが、これはそうではありません... – user3368561

答えて

3

2番目の例は有効ではないC99で、C++と似ています。おそらく、キャストが欲しい、つまり(int32_t)(a/UINT64_C(1000000000))ですか?

a/UINT64_C(1000000000)a/1000000000の間に違いはありますか?いいえ、彼らは同じ操作で終わるでしょう。しかし、私はそれが本当にあなたの質問だとは思わない。

あなたの質問は、整数リテラル "1000000000"の型はどうなるのでしょうか?それはint32_tかint64_tですか? C99の答えは、6.4.4.1段落5から得られます。

整数定数の型は、その値を表すことができる対応するリストの最初です。接尾辞なしの10進定数については

、リストはintlong intlong long intです。したがって、最初のリテラルはほぼ確実にintintのサイズに依存しますが、これはおそらく32ビットで10億を保持するのに十分な大きさです)。 UINT64_Cマクロの2番目のリテラルは、プラットフォームによってはunsigned longまたはunsigned long longのいずれかになります。 uint64_tに対応するどんなタイプでもなります。

したがって、定数の型は同じではありません。最初のものは署名され、2番目のものは署名されません。 2番目のコンパイラは、基本的なint型のコンパイラのサイズに応じて、より多くの「longs」を持つ可能性が高くなります。あなたの例では

、それは(aはどのような場合にはリテラルと同等またはそれ以上のランクのものであろうので)/オペレータがaのタイプにリテラルを推進する必要がありますので、リテラルは、異なる種類を持っているという違いはありません。だから私はそれが本当にあなたの質問だとは思わなかったのです。

UINT64_C()が重要な理由の例として、リテラルがより大きな型に昇格された場合に結果が変化する式を考えてみましょう。つまり、リテラルのネイティブタイプでオーバーフローが発生します。cを計算するために

int32_t a = 10; 
uint64_t b = 1000000000 * a; // overflows 32-bits 
uint64_t c = UINT64_C(1000000000) * a; // constant is 64-bit, no overflow 

、コンパイラはuint64_tからaを促進し、64ビットの乗算を実行する必要があります。しかし、bを計算するには、両方の値が32ビットであるため、コンパイラは32ビット乗算を使用します。

uint64_t c = (uint_least64_t)(1000000000) * a; 

また乗算は、少なくとも64ビットであることを強制する:最後の例で

は一つではなくマクロのキャストを使用することができます。

リテラルをキャストする代わりにマクロを使用するのはなぜですか? 1つの可能性は、小数のリテラルが署名されているためです。符号付きの値として表現できない定数が必要だとします。たとえば、

uint64_t x = (uint64_t)9888777666555444333; // warning, literal is too large 
uint64_t y = UINT64_C(9888777666555444333); // works 
uint64_t z = (uint64_t)(9888777666555444333U); // also works 

プリプロセッサ式の可能性もあります。キャストは、#ifディレクティブの表現に使用する正当な構文ではありません。しかし、UINTxx_C()マクロはあります。

マクロはリテラルに貼り付けられた接尾辞を使用しているため、接尾辞はありません。UINT16_C(x)とUINT32_C(x)は同じである可能性があります。これにより、結果は(uint_least16_t)(65537) != UINT16_C(65537)となります。誰かが期待するものではありません。

マクロUINTN_C(値)型uint_leastN_tに対応する整数定数式に展開されなければならない。実際、私はこれはC99§7.18.4.1に準拠していますどのように苦労を見ています。

+0

私は質問を明確にするために更新しました。 – user3368561

+0

'uint16_t x;'を指定すると、コンパイラは 'x = UINT16_C(65539);' x = 65539; 'に対して発行しない診断を発行するでしょうか?後者は振る舞いを定義していましたが(xを3に設定)、場合によっては診断がより意味があるかもしれません。 – supercat

+0

'UINT16_C(65539)'は符号なしで '65539'が署名されているので、暗黙的に符号付きから符号なしに変換することができます。より関連性が高いのは、リテラルをuint16_tに暗黙的に変換する際のオーバーフローであり、いずれの場合もそうなるでしょう。変換はもはや暗黙的ではないので、 'x =(uint16_t)65539; 'で生成されることはありません。 – TrentP

関連する問題