C++で符号なし8ビット変数を使用したい。算術に関する限り、unsigned char
またはuint8_t
のいずれかがトリックを行います(AFAIK uint8_t
はunsigned char
の単なるエイリアスであるため、デバッガーが提示します)。
問題は、C++でostreamを使用して変数を出力すると、charとして処理されることです。私が持っている場合:
unsigned char a = 0;
unsigned char b = 0xff;
cout << "a is " << hex << a <<"; b is " << hex << b << endl;
出力は次のとおりです。
a is ^@; b is 377
の代わりに
a is 0; b is ff
uint8_t
を使用してみましたが、前述したように、それはunsigned char
にtypedefされているので、同じことを行います。変数を正しく印刷するにはどうすればよいですか?
編集:コード全体の多くの場所でこれを行います。これを行う方法はありますかwithout印刷するたびにint
にキャストしますか?
次の手法を使用することをお勧めします。
struct HexCharStruct
{
unsigned char c;
HexCharStruct(unsigned char _c) : c(_c) { }
};
inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs)
{
return (o << std::hex << (int)hs.c);
}
inline HexCharStruct hex(unsigned char _c)
{
return HexCharStruct(_c);
}
int main()
{
char a = 131;
std::cout << hex(a) << std::endl;
}
書くのは短く、元のソリューションと同じ効率があり、「元の」文字出力を使用することを選択できます。そして、それはタイプセーフです(「悪」マクロを使用しません:-))
つかいます:
cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl;
そして、先行ゼロでパディングしたい場合:
#include <iomanip>
...
cout << "a is " << setw(2) << setfill('0') << hex << (int) a ;
Cスタイルのキャストを使用しているので、C++の最終的な悪さを十分に理解し、マクロを使用してみませんか。
#define HEX( x )
setw(2) << setfill('0') << hex << (int)( x )
あなたはその後言うことができます
cout << "a is " << HEX( a );
編集:とは言っても、MartinStettnerのソリューションははるかに優れています!
詳細については http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ および- http://cpp.indi.frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/ 。上記の記事の著者が意図していないことが明らかになったため、私はこれを投稿しています。
文字を16進数として印刷する最も簡単で正しいテクニックは次のとおりです。
unsigned char a = 0;
unsigned char b = 0xff;
auto flags = cout.flags(); //I only include resetting the ioflags because so
//many answers on this page call functions where
//flags are changed and leave no way to
//return them to the state they were in before
//the function call
cout << "a is " << hex << +a <<"; b is " << +b << endl;
cout.flags(flags);
読者がこれがどのように機能するかをダイジェスト版は、単項+演算子が正しい符号付きのintにno op型変換を強制することです。したがって、unsigned charはunsigned intに変換され、signed charはintに変換され、charはプラットフォームでcharが署名されているか署名されていないかに応じてunsigned intまたはintに変換されます署名済みまたは署名なしとして指定されていません)。
この手法の唯一の欠点は、慣れていない人に何が起こっているのかがはっきりしない場合があることです。しかし、間違っているがすぐに明確なことをするよりも、正しいテクニックを使用し、他の人にそれを教える方が良いと思います。
まあ、これは私のために働く:
std::cout << std::hex << (0xFF & a) << std::endl;
単に(int)
推奨されるように、最上位ビットが1の場合、a
の左に1を追加する場合があります。 coutを強制的に16進数として印刷します。
これがお役に立てば幸いです。
ええと、昨日ホイールを再発明したようです...しかし、ちょっと、少なくとも今回は一般的なホイールです:) char
sは2桁の16進数で印刷され、short
sは4桁の16進数等々。
template<typename T>
struct hex_t
{
T x;
};
template<typename T>
hex_t<T> hex(T x)
{
hex_t<T> h = {x};
return h;
}
template<typename T>
std::ostream& operator<<(std::ostream& os, hex_t<T> h)
{
char buffer[2 * sizeof(T)];
for (auto i = sizeof buffer; i--; )
{
buffer[i] = "0123456789ABCDEF"[h.x & 15];
h.x >>= 4;
}
os.write(buffer, sizeof buffer);
return os;
}
TrungTNとanonの答えは大丈夫だと思いますが、hex()関数を実装するMartinStettnerの方法は本当に単純ではなく、hex <<(int)mycharがすでに回避策であることを考えると暗すぎます。
「<<」演算子を簡単にするための私のソリューションは次のとおりです。
#include <sstream>
#include <iomanip>
string uchar2hex(unsigned char inchar)
{
ostringstream oss (ostringstream::out);
oss << setw(2) << setfill('0') << hex << (int)(inchar);
return oss.str();
}
int main()
{
unsigned char a = 131;
std::cout << uchar2hex(a) << std::endl;
}
ストリーム演算子を実装するだけの価値はありません:-)
私はMartinStettnerのようにしますが、桁数に追加のパラメーターを追加します。
inline HexStruct hex(long n, int w=2)
{
return HexStruct(n, w);
}
// Rest of implementation is left as an exercise for the reader
したがって、デフォルトでは2桁ですが、必要に応じて4、8などを設定できます。
例えば。
int main()
{
short a = 3142;
std:cout << hex(a,4) << std::endl;
}
やり過ぎのように見えるかもしれませんが、Bjarneが言ったように、「ライブラリは使いやすく、書くのは簡単ではないはずです」。
私はwin32/linux(32/64ビット)で以下を使用します:
#include <iostream>
#include <iomanip>
template <typename T>
std::string HexToString(T uval)
{
std::stringstream ss;
ss << "0x" << std::setw(sizeof(uval) * 2) << std::setfill('0') << std::hex << +uval;
return ss.str();
}
次のコードを試すことができます:
unsigned char a = 0;
unsigned char b = 0xff;
cout << hex << "a is " << int(a) << "; b is " << int(b) << endl;
cout << hex
<< "a is " << setfill('0') << setw(2) << int(a)
<< "; b is " << setfill('0') << setw(2) << int(b)
<< endl;
cout << hex << uppercase
<< "a is " << setfill('0') << setw(2) << int(a)
<< "; b is " << setfill('0') << setw(2) << int(b)
<< endl;
出力:
a is 0; b is ff
a is 00; b is ff
a is 00; b is FF
これは古い質問ですが、テンプレートクラス内で任意の整数から16進文字列への変換を実装したいという非常によく似た問題の解決策を模索する上で、Googleのトップの結果でもあります。私の最終目標は、実際にGtk::Entry
さまざまな整数幅を16進数で編集できるサブクラステンプレートですが、それはポイントの横にあります。
これは単項operator+
トリックstd::make_unsigned
from <type_traits>
符号拡張ネガティブの問題を防ぐためにint8_t
または signed char
この回答 で発生する値
とにかく、これは他の一般的なソリューションよりも簡潔だと思います。 any符号付きまたは符号なし整数型で機能し、非整数型で関数をインスタンス化しようとするとコンパイル時エラーがスローされます。
template <
typename T,
typename = typename std::enable_if<std::is_integral<T>::value, T>::type
>
std::string toHexString(const T v)
{
std::ostringstream oss;
oss << std::hex << +((typename std::make_unsigned<T>::type)v);
return oss.str();
}
使用例:
int main(int argc, char**argv)
{
int16_t val;
// Prints 'ff' instead of "ffffffff". Unlike the other answer using the '+'
// operator to extend sizeof(char) int types to int/unsigned int
std::cout << toHexString(int8_t(-1)) << std::endl;
// Works with any integer type
std::cout << toHexString(int16_t(0xCAFE)) << std::endl;
// You can use setw and setfill with strings too -OR-
// the toHexString could easily have parameters added to do that.
std::cout << std::setw(8) << std::setfill('0') <<
toHexString(int(100)) << std::endl;
return 0;
}
Update:または、ostringstream
が使用されているという考えが気に入らない場合は、テンプレートと単項演算子のトリックを組み合わせることができます。次の受け入れられた答えの構造ベースのソリューションで。ここでは、整数型のチェックを削除してテンプレートを変更したことに注意してください。 make_unsigned
の使用は、コンパイル時の型の安全性を保証するのに十分かもしれません。
template <typename T>
struct HexValue
{
T value;
HexValue(T _v) : value(_v) { }
};
template <typename T>
inline std::ostream& operator<<(std::ostream& o, const HexValue<T>& hs)
{
return o << std::hex << +((typename std::make_unsigned<T>::type) hs.value);
}
template <typename T>
const HexValue<T> toHex(const T val)
{
return HexValue<T>(val);
}
// Usage:
std::cout << toHex(int8_t(-1)) << std::endl;
@FredOverflowに基づいて再発明したバージョンを投稿したいと思います。次の変更を加えました。
修正:
operator<<
_のRhsは、const
参照型でなければなりません。 @FredOverflowのコードでは、_h.x >>= 4
_が出力h
を変更します。これは驚くべきことに標準ライブラリと互換性がなく、タイプT
はコピー構築可能に再作成されます。CHAR_BITS
_のみが4の倍数であると想定します。@ FredOverflowのコードはchar
が8ビットであると想定しています。これは、DSPの実装によっては必ずしも当てはまりません。特に、char
は16ビット、24ビット、32ビットなどです。改善する:
std::uppercase
_。形式出力は__print_byte
_で使用されるため、標準ライブラリマニピュレーターは引き続き使用可能です。hex_sep
_を追加して、個別のバイトを印刷します(C/C++では、「バイト」はサイズがchar
のストレージユニットであることに注意してください)。テンプレートパラメータSep
を追加し、hex
および__Hex<T, false>
_にそれぞれ__Hex<T, true>
_および_hex_sep
_をインスタンス化します。_print_byte
_は、_operator<<
_から関数パラメーターsize
で抽出され、異なるSize
のインスタンス化を回避します。バイナリコードの肥大化の詳細:
改善3で述べたように、hex
および_hex_sep
_がどれほど広範囲に使用されても、(ほぼ)複製された関数の2つのコピーのみがバイナリコードで終了します:__print_byte<true>
_および__print_byte<false>
_ 。そして、あなたは、この重複もまったく同じアプローチを使用して排除できることに気付くかもしれません:関数パラメーターsep
を追加します。はい。ただし、そうする場合、ランタイムif(sep)
が必要です。プログラムで広く使用される可能性のある共通ライブラリユーティリティが必要なため、ランタイムオーバーヘッドではなく複製で妥協しました。コンパイル時にif
:C++ 11 _std::conditional
_を使用することでこれを達成しました。関数呼び出しのオーバーヘッドはinline
によって最適化されます。
hex_print.h:
_namespace Hex
{
typedef unsigned char Byte;
template <typename T, bool Sep> struct _Hex
{
_Hex(const T& t) : val(t)
{}
const T& val;
};
template <typename T, bool Sep>
std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h);
}
template <typename T> Hex::_Hex<T, false> hex(const T& x)
{ return Hex::_Hex<T, false>(x); }
template <typename T> Hex::_Hex<T, true> hex_sep(const T& x)
{ return Hex::_Hex<T, true>(x); }
#include "misc.tcc"
_
hex_print.tcc:
_namespace Hex
{
struct Put_space {
static inline void run(std::ostream& os) { os << ' '; }
};
struct No_op {
static inline void run(std::ostream& os) {}
};
#if (CHAR_BIT & 3) // can use C++11 static_assert, but no real advantage here
#error "hex print utility need CHAR_BIT to be a multiple of 4"
#endif
static const size_t width = CHAR_BIT >> 2;
template <bool Sep>
std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size)
{
using namespace std;
auto pbyte = reinterpret_cast<const Byte*>(ptr);
os << hex << setfill('0');
for (int i = size; --i >= 0; )
{
os << setw(width) << static_cast<short>(pbyte[i]);
conditional<Sep, Put_space, No_op>::type::run(os);
}
return os << setfill(' ') << dec;
}
template <typename T, bool Sep>
inline std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h)
{
return _print_byte<Sep>(os, &h.val, sizeof(T));
}
}
_
テスト:
_struct { int x; } output = {0xdeadbeef};
cout << hex_sep(output) << std::uppercase << hex(output) << endl;
_
出力:
_de ad be ef DEADBEEF
_