目次: C言語とlibc
コンピュータで負の値を表現するときは「2の補数を使います」と習った方は多いと思います。C言語もそうでしょうか?
答えは「いいえ。そして、はい。」です。
「いいえ。」の方は、整数型intやlongです。これらの型は2の補数とは限りません。sign and magnitudeや、1の補数表現が許されます。符号と値だけでなく、意味のないビット(パディングビット)の存在も許されています。C11 committee draftの6.2.6.2の定義を見ましょう。
6.2.6.2 Integer types 1 (unsigned系の話なので省略) 2 For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; signed char shall not have any padding bits. There shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M <= N). If the sign bit is zero, it shall not affect the resulting value. If the sign bit is one, the value shall be modified in one of the following ways: - the corresponding value with sign bit 0 is negated (sign and magnitude); - the sign bit has the value -(2^M ) (two’s complement); - the sign bit has the value -(2^M - 1) (ones’ complement). Which of these applies is implementation-defined, as is whether the value with sign bit 1 and all value bits zero (for the first two), or with sign bit and all value bits 1 (for one's complement), is a trap representation or a normal value. In the case of sign and magnitude and ones’ complement, if this representation is a normal value it is called a negative zero.
この節は何を言っているのかすこぶるわかりにくいので、ざっくり和訳と具体例を載せます。わかりやすくなっていると嬉しいです。間違いがあったら教えていただけると嬉しいです。
6.2.6.2 Integer types 1省略 2符号付き整数型の場合、オブジェクト表現のビットは、値ビット、パディングビット、符号ビットの3つのグループに分けなければならない。 パディングビットは持っても持たなくても構わないが、符号付きchar型はパディングビットをもってはならない。符号ビットは1ビットで なければならない。値ビットの各ビットは、対応する符号なし型のオブジェクト表現と同じビットでなければならない。 (もし符号付き型にMビットの値ビットがあって、符号なし型にNビットの値ビットがあるなら、M <= Nである) 符号ビットが0なら結果の値には影響しない。符号ビットが1なら、値は次のいずれかの方法で修正されなければならない。 - 符号ビットが0の時の値がそのまま負の値(sign and magnitude) (例) 10000000 -> -0 ←負のゼロ、もしくはトラップ 10000001 -> -1 10000010 -> -2 ... 11111101 -> -125 11111110 -> -126 11111111 -> -127 - 符号ビットが -(2^M) の値(2の補数) (例) 10000000 -> -128 10000001 -> -127 10000010 -> -126 ... 11111101 -> -3 11111110 -> -2 11111111 -> -1 - 符号ビットが -(2^M - 1) の値(1の補数) (例) 10000000 -> -127 10000001 -> -126 10000010 -> -125 ... 11111101 -> -2 11111110 -> -1 11111111 -> -0 ←負のゼロ、もしくはトラップ このうちどれを適用するかは実装依存である。符号ビットが1で値ビットが全て0(sign and magnitudeと2の補数のとき)、 もしくは符号ビットと値ビットが全て1(1の補数のとき)を持つ値が、トラップ表現か正常な表現かについても同様に実装依存である。 sign and magnitudeと1の補数の場合は、この表現を正常な値とするなら、その値は「負のゼロ(negative zero)」と 呼ばれる。
負の値を表現する方法はいくつかあって、今はほぼ全てのアーキテクチャで2の補数が一般的です。しかし古いアーキテクチャではsign and magnitudeや1の補数を採用していたものがあったのかもしれませんね。
「はい。」の方は、C99で登場した新しい整数型(intN_tのような型)です。こちらは2の補数、パディングビットなしの割り切った仕様です。しかし一般的に良く使われているint8_t, int16_t, int32_tが必ず使えるとは限らないことに注意が必要です。
7.20.1.1 Exact-width integer types 1 The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes such a signed integer type with a width of exactly 8 bits. 2 The typedef name uintN_t designates an unsigned integer type with width N and no padding bits. Thus, uint24_t denotes such an unsigned integer type with a width of exactly 24 bits. 3 These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two's complement representation, it shall define the corresponding typedef names. (ざっくり和訳) 1型名intN_tは、幅N、パディングビットなし、2の補数表現の符号付き整数型であることを示す。 したがってint8_tは、幅が正確に8ビットの符号付き整数型を示す。 2型名uintN_tは、幅N、パディングビットなし、2の補数表現の符号なし整数型であることを示す。 したがってuint24_tは、幅が正確に24ビットの符号付き整数型を示す。 3これらの型はオプションである。しかし実装が8, 16, 32, 64ビット、パディングビットなし、 2の補数表現(符号付きの場合)を持つ整数型を提供する場合は、対応するtypedef名を定義しなければならない。
現代のアーキテクチャに合わせてsign and magnitudeと1の補数をバッサリ切った雰囲気を感じます。仕様で気になるのは3ですね。optionalで実装依存とおっしゃっています。これは困ります……。
確実を期すならint_least32_t(規格上requiredなので)を使えば良いですが、最低でも32bitだと仕様として不便です。本当は何bitですか?を求める処理を書かねばならないでしょう。名前も長くて使いにくいですし。
< | 2022 | > | ||||
<< | < | 09 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | - |
合計:
本日: