まずJavaのコードで
java
1int id = -104;//152でも同じ 2ByteBuffer buffer = ByteBuffer.allocate(4); 3buffer.putInt(id); 4buffer.array()[3]; //=> -104
というのがあります。これをC++11に移植することを考えています。
Javaがビッグエンディアンであることを踏まえて、リトルエンディアンな環境を仮定すれば
cpp
1std::int32_t id = -104; 2reinterpret_cast<std::uint8_t*>(&id)[0];// => 152
と書けそうですが、できればリトルエンディアンな環境を仮定したくないですし、かといってそもそもエンディアンの判定自体やりたくないです。
ところでWandboxで
cpp
1#include <cstdint> 2#include <iostream> 3int main() 4{ 5 std::int32_t n = -104; 6 std::uint8_t n2 = reinterpret_cast<uint8_t*>(&n)[0]; 7 std::cout << int(n2) << ' ' << int(static_cast<uint8_t>(n)) << std::endl;// => 152 152 8}
https://wandbox.org/permlink/jzFflPh8RZSFWOjI
というコードを走らせるとstatic_cast<uint8_t>(n)
でもいい気がします。
しかしこれはどういう仕様で変換されるのか理解できていません。
N3337の§4.7 [conv.integral]には
- A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped
enumeration type can be converted to a prvalue of an integer type.
- If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source
integer (modulo 2 n where n is the number of bits used to represent the unsigned type).
とありますが、イマイチ理解できず、江添本では
変換先の整数型がunsignedの場合、結果の値は、変換元の対応する下位桁の値である。
具体的な例を示して説明する。
cpp
1// unsigned charが8ビット、unsigned intが16ビットとする 2 3int main() 4{ 5 unsigned int ui = 1234 ; 6 unsigned char uc = ui ; // 210 7}
この場合、unsigned int型は、16ビット、uiの値は、2進数で0000010011010010である。unsigned char型は8ビット。つまり、この場合の対応する下位桁の値は、2進数で11010010(uiの下位8ビット)である。よって、ucは、10進数で210となる。
とありますが、例がunsigned -> unsignedでsigned -> unsignedへの言及がありません。
結局のところ、
cpp
1std::int32_t id = -104; 2static_cast<std::uint8_t>(id);// => 152
は常に期待できる動作なのでしょうか?
C++ における整数型の怪と "移植性のある" オーバーフローチェッカー (第1回 : 整数型の怪と対策の不足) - Qiita#C 言語 (C99) における整数型の定義
通常の整数型とは別に、stdint.h
のint8_t
、int16_t
、int32_t
、int64_t
といったビット固定の符号付き整数型が存在する場合があります。これらのビット数固定符号付き整数型に限っては、存在すれば必ず 2 の補数表現であることが保証されており、データ型の移植性を飛躍的に高めることができます。
質問の書き方だと2の補数表現な処理系を暗黙に仮定していましたが、仮定していいことにします
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/05/31 02:41