C/C++の梱包signed charへのint
質問
していま必要なパック四つの署名バイトを32ビット整数タイプです。そのために:
int32_t byte(int8_t c) { return (unsigned char)c; }
int pack(char c0, char c1, ...) {
return byte(c0) | byte(c1) << 8 | ...;
}
このソリューション?で片手で持つことがない感覚)?ですが、既製のソリューションにも力?
問い主の関心はビットの順序を換算するときに負のビットからcharのint.このホテルはハノイ(ドンダーの正しい行動をすべきます。
感謝
解決
私はそれが(多くの状況で本当の痛みを引き起こす)マクロで書かれているという事実を除いてジョーイアダムの答えが好きで、「charは」1バイト幅でない場合、コンパイラはあなたに警告を与えることはありません。これは、(ジョーイのオフに基づいて)私の解決策である。
inline uint32_t PACK(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) {
return (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
}
inline uint32_t PACK(sint8_t c0, sint8_t c1, sint8_t c2, sint8_t c3) {
return PACK((uint8_t)c0, (uint8_t)c1, (uint8_t)c2, (uint8_t)c3);
}
シフトするとき、私はあなたのためにこれを処理する必要があり、コンパイラなどのuint32_tに鋳造C0-> C3を省略していると私は、彼らがCまたはC ++(両方としてタグ付けされたOP)のいずれかのために働くだろうとCスタイルキャストを使用しました。
他のヒント
char
なる保証をする署名または符号なし(PowerPC-Linux、charデフォルト 符号なし).ソーシャルメディア
何をしたいというようにこのマクロ:
#include <stdint.h> /* Needed for uint32_t and uint8_t */
#define PACK(c0, c1, c2, c3) \
(((uint32_t)(uint8_t)(c0) << 24) | \
((uint32_t)(uint8_t)(c1) << 16) | \
((uint32_t)(uint8_t)(c2) << 8) | \
((uint32_t)(uint8_t)(c3)))
ころがいなくなってしまったことは、我々は、Cの順です。また、バックスラッシュ-を返しますがこのマクロな大きな長蛇の列が出来ていました。
また、このキャストuint8_t前に鋳造uint32_tが不要なサイン。
あなたは暗黙の型変換とキャストを避けることができます:
uint32_t pack_helper(uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3) {
return c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
}
uint32_t pack(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) {
return pack_helper(c0, c1, c2, c3);
}
アイデアは、あなたが見る「正しくすべてのパラメータを変換します。シフトし、それらを組み合わせた」ということです「それを正しく変換し、シフトとそれを組み合わせる、各パラメータのために」のではなく、。あまりそれで、しかします。
するとます:
template <int N>
uint8_t unpack_u(uint32_t packed) {
// cast to avoid potential warnings for implicit narrowing conversion
return static_cast<uint8_t>(packed >> (N*8));
}
template <int N>
int8_t unpack_s(uint32_t packed) {
uint8_t r = unpack_u<N>(packed);
return (r <= 127 ? r : r - 256); // thanks to caf
}
int main() {
uint32_t x = pack(4,5,6,-7);
std::cout << (int)unpack_u<0>(x) << "\n";
std::cout << (int)unpack_s<1>(x) << "\n";
std::cout << (int)unpack_u<3>(x) << "\n";
std::cout << (int)unpack_s<3>(x) << "\n";
}
出力:
4
5
249
-7
このはuint32_t
、uint8_t
とint8_t
タイプなどのような携帯型です。それらのいずれもC99に必要とされず、ヘッダstdint.hは、C ++またはC89で定義されていません。種類が存在し、C99の要件を満たしている場合は、しかし、コードが動作します。もちろんCにアンパック関数は、関数パラメータの代わりに、テンプレートパラメータが必要になります。あなたは開梱のための短いループを書きたい場合は、あまりにもC ++のそれを好むかもしれません。
タイプはオプションであるという事実に対処するために、あなたがC99で必要とされるuint_least32_t
を、使用することができます。同様にuint_least8_t
とint_least8_t
。あなたはpack_helperとunpack_uのコードを変更する必要があります:
uint_least32_t mask(uint_least32_t x) { return x & 0xFF; }
uint_least32_t pack_helper(uint_least32_t c0, uint_least32_t c1, uint_least32_t c2, uint_least32_t c3) {
return mask(c0) | (mask(c1) << 8) | (mask(c2) << 16) | (mask(c3) << 24);
}
template <int N>
uint_least8_t unpack_u(uint_least32_t packed) {
// cast to avoid potential warnings for implicit narrowing conversion
return static_cast<uint_least8_t>(mask(packed >> (N*8)));
}
これはそれだけの価値になることはほとんどありません正直に言うと - チャンスはあなたのアプリケーションの残りの部分が存在しないなどのint8_t
前提に書かれています。これは、8ビットと32ビットの2の補数形式を持っていない希少な実装です。
"良さ"
まぁ、このベストソリューションをつけよう。編集:もっ利用 static_cast<unsigned int>
ではなく、Cスタイル鋳ていただきたいと思いますか使用しないで別の非表示にする方法、キャスト....
携帯性:
ができない携帯することでも char
する最上位ビットは、何もしない unsigned int
ニーズを4バイトの幅です。
さらに、だけを頼りにendiannessは、そのためのデータパックもワン-アーキテクチャできないことに反対endianness.
ですが、既製のソリューションにも力?
なんで気が付いている。
これはグラントピーターズとジョーイアダムス回答に基づいており、(アンパック関数はCで符号なしの値のモジュロルールに依存して)署名された値をアンパックする方法を示すように拡張
(スティーブジェソップコメントで述べたように、別個pack_s
とpack_u
機能は不要である)。
inline uint32_t pack(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3)
{
return ((uint32_t)c0 << 24) | ((uint32_t)c1 << 16) |
((uint32_t)c2 << 8) | (uint32_t)c3;
}
inline uint8_t unpack_c3_u(uint32_t p)
{
return p >> 24;
}
inline uint8_t unpack_c2_u(uint32_t p)
{
return p >> 16;
}
inline uint8_t unpack_c1_u(uint32_t p)
{
return p >> 8;
}
inline uint8_t unpack_c0_u(uint32_t p)
{
return p;
}
inline uint8_t unpack_c3_s(uint32_t p)
{
int t = unpack_c3_u(p);
return t <= 127 ? t : t - 256;
}
inline uint8_t unpack_c2_s(uint32_t p)
{
int t = unpack_c2_u(p);
return t <= 127 ? t : t - 256;
}
inline uint8_t unpack_c1_s(uint32_t p)
{
int t = unpack_c1_u(p);
return t <= 127 ? t : t - 256;
}
inline uint8_t unpack_c0_s(uint32_t p)
{
int t = unpack_c0_u(p);
return t <= 127 ? t : t - 256;
}
(後者の値が127を超える場合、実装定義信号を上昇させることができるので、これらは、単にバックint8_t
に鋳造ではなく必要であり、それは厳密に携帯用ではない)。
また、コンパイラがあなたのために仕事をさせことができます。
union packedchars {
struct {
char v1,v2,v3,v4;
}
int data;
};
packedchars value;
value.data = 0;
value.v1 = 'a';
value.v2 = 'b;
など