C++03/11/14/17/20 各々の言語仕様を使いつつ実装すると勉強になります。
実装対象をビッグ エンディアンとリトル エンディアンに限定します。
動作確認は
- macOS 14.5
- Apple clang version 15.0.0 (clang-1500.3.9.4)
- Target: x86_64-apple-darwin23.5.0
- Apple clang version 15.0.0 (clang-1500.3.9.4)
なので、ビッグ エンディアン機でのテストはしていません。
C++20 より前でも std::endian と std::byteswap を用意
ヘッダ ファイル : endian.hpp
#pragma once
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L
#include <bit>
#endif
#if __cpp_lib_endian < 201907L
#if !(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && defined(__ORDER_LITTLE_ENDIAN__))
# if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(_M_ARM)
# define __ORDER_BIG_ENDIAN__ 4321
# define __ORDER_LITTLE_ENDIAN__ 1234
# define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
# else
# error "unknown compiler."
# endif
#endif
namespace std
{
#if __cplusplus < 201103L && _MSVC_LANG < 201103L
struct endian
{
enum value_type
{
big = __ORDER_BIG_ENDIAN__,
little = __ORDER_LITTLE_ENDIAN__,
native = __BYTE_ORDER__,
};
};
#else /* C++11 */
enum class endian
{
big = __ORDER_BIG_ENDIAN__,
little = __ORDER_LITTLE_ENDIAN__,
native = __BYTE_ORDER__,
};
#endif /* C++11 */
} // std
#endif /* __cpp_lib_endian < 201907L */
ヘッダ ファイル : byteswap.hpp
#pragma once
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L
#include <bit>
#endif
#if __cpp_lib_byteswap < 202110L
namespace std
{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4293 4333 26452)
#endif /* MSVC */
template <typename T>
#if __cplusplus < 201103L && _MSVC_LANG < 201103L
inline
# if defined(__GNUC__) || defined(__clang__)
__attribute__((const, pure))
# endif
T byteswap(T x)
#else /* C++11 */
inline constexpr T byteswap(T x) noexcept
#endif
{
return (sizeof(T) == 8
? T((((x >> 000) & 0xff) << 070) |
(((x >> 010) & 0xff) << 060) |
(((x >> 020) & 0xff) << 050) |
(((x >> 030) & 0xff) << 040) |
(((x >> 040) & 0xff) << 030) |
(((x >> 050) & 0xff) << 020) |
(((x >> 060) & 0xff) << 010) |
(((x >> 070) & 0xff) << 000))
: sizeof(T) == 4
? T((((x >> 000) & 0xff) << 030) |
(((x >> 010) & 0xff) << 020) |
(((x >> 020) & 0xff) << 010) |
(((x >> 030) & 0xff) << 000))
: sizeof(T) == 2
? T((((x >> 000) & 0xff) << 010) |
(((x >> 010) & 0xff) << 000))
: x);
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif /* MSVC */
} // std
#endif /* __cpp_lib_byteswap < 202110L */
実装方法
- C++03 でも std::conditional が使用可能な処理系を前提としています。
まず、(整数/浮動小数点/文字)型 T
をテンプレート引数とするクラス byteswap_value 作ります。
template <typename T> class byteswap_value;
CPU が直接扱う型を native_endian::型
で参照できるようにします。
struct native_endian {
enum {
is_big = std::endian::big == std::endian::native,
is_little = std::endian::little == std::endian::native,
};
typedef std::int8_t int8_type;
typedef std::uint8_t uint8_type;
typedef std::int16_t int16_type;
typedef std::uint16_t uint16_type;
// ...(略)...
};
これに対応する byteswap 型を byteswap_endian::型
で参照できるようにします。
struct byteswap_endian {
enum {
is_big = !native_endian::is_big,
is_little = !native_endian::is_little,
};
typedef native_endian::int8_type int8_type;
typedef native_endian::uint8_type uint8_type;
typedef byteswap_value<native_endian::int16_type> int16_type;
typedef byteswap_value<native_endian::uint16_type> uint16_type;
// ...(略)...
};
native_endian
か byteswap_endian
を選択するためのテンプレート fixed_endian
を用意します。
template <bool big_endian>
struct fixed_endian : std::conditional<
big_endian == native_endian::is_big,
native_endian, byteswap_endian>::type {};
ビッグ エンディアンは_t
の前にbe
を付けてbe_t
に、同様にリトル エンディアンはle_t
とする型を定義します。
typedef fixed_endian<true> big_endian;
typedef big_endian::int8_type int8be_t;
typedef big_endian::uint8_type uint8be_t;
typedef big_endian::int16_type int16be_t;
typedef big_endian::uint16_type uint16be_t;
// ...(略)...
typedef fixed_endian<false> little_endian;
typedef little_endian::int8_type int8le_t;
typedef little_endian::uint8_type uint8le_t;
typedef little_endian::int16_type int16le_t;
typedef little_endian::uint16_type uint16le_t;
// ...(略)...
C++03 で書いてみる
初期化にはコンストラクタが必要
byteswap_value<int> sw(1);
byteswap_value<int> sw = 1;
だから、コンストラクタを定義すると trivial 型ではなくなる。すると、
std::basic_string< byteswap_value<wchar_t> >
は clang++
ではコンパイル エラーが出る。
二項(T型とU型の)演算の返り値の型推定が少し面倒だった。
- (int, T, U) の中で一番大きい正の数を表現できる型
template <typename T>
class byteswap_value
{
public:
typedef T value_type; // byteswap する native の型.
protected:
/* T が整数型時の情報 */
template <typename I>
struct integer_type
{
enum {
is_signed = std::numeric_limits<I>::is_signed,
bits = sizeof(I) * 8 - (is_signed ? 1 : 0),
};
typedef I type;
};
/* T が浮動小数点型時の情報 */
template <typename I, int B>
struct floating_type
{
enum { bits = B };
typedef I type;
};
/* 逆バイト順型 */
template <typename I> struct bswap : integer_type<I> {};
template <> struct bswap<float> : floating_type<std::uint32_t, 128> {};
template <> struct bswap<double> : floating_type<std::uint64_t, 1024> {};
typedef typename bswap<T>::type bswap_value; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline bswap_cast(const T& n) : v(n) {}
inline operator bswap_value() const
{ return std::byteswap(*(const bswap_value*)&v); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline native_cast(const bswap_value& s) : v(std::byteswap(s)) {}
inline operator T() const { return *(const T*)&v; }
};
protected:
/* 二項演算結果の型推定 */
template <typename U>
struct retval
{
template <typename V> struct chrint { typedef V type; };
template <> struct chrint<wchar_t> { typedef wint_t type; };
enum {
t_bits = bswap<T>::bits,
u_bits = bswap<U>::bits,
t_flag = t_bits > u_bits,
r_bits = t_flag ? t_bits : u_bits,
i_bits = bswap<int>::bits,
r_flag = r_bits > i_bits,
};
typedef typename std::conditional<t_flag, T, U>::type R;
typedef typename std::conditional<r_flag, R, int>::type V;
typedef typename chrint<V>::type type;
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
inline byteswap_value() {}
inline byteswap_value(T d) : _v(bswap_cast(d)) {}
inline byteswap_value(const byteswap_value<T>& s) : _v(s._v) {}
inline operator T() const { return get(); }
inline bool operator !() const { return !_v; }
inline bool operator ==(const byteswap_value<T>& s) const { return _v == s._v; }
inline bool operator !=(const byteswap_value<T>& s) const { return _v != s._v; }
template <typename U> inline bool operator < (U n) const { return get() < n; }
template <typename U> inline bool operator <=(U n) const { return get() <= n; }
template <typename U> inline bool operator ==(U n) const { return get() == n; }
template <typename U> inline bool operator !=(U n) const { return get() != n; }
template <typename U> inline bool operator >=(U n) const { return get() >= n; }
template <typename U> inline bool operator > (U n) const { return get() > n; }
inline T operator +() const { return +get(); }
inline T operator -() const { return -get(); }
inline T operator ~() const { return ~get(); }
template <typename U> inline typename retval<U>::type operator +(U n) const { return get() + n; }
template <typename U> inline typename retval<U>::type operator -(U n) const { return get() - n; }
template <typename U> inline typename retval<U>::type operator *(U n) const { return get() * n; }
template <typename U> inline typename retval<U>::type operator /(U n) const { return get() / n; }
template <typename U> inline typename retval<U>::type operator %(U n) const { return get() % n; }
template <typename U> inline typename retval<U>::type operator &(U n) const { return get() & n; }
template <typename U> inline typename retval<U>::type operator |(U n) const { return get() | n; }
template <typename U> inline typename retval<U>::type operator ^(U n) const { return get() ^ n; }
inline T operator <<(int n) const { return get() << n; }
inline T operator >>(int n) const { return get() >> n; }
inline byteswap_value<T>& operator =(T n) { return set(n); }
inline byteswap_value<T>& operator =(const byteswap_value<T>& s) { _v = s._v; return *this; }
template <typename U> inline byteswap_value<T>& operator +=(U n) { return set(get() + n); }
template <typename U> inline byteswap_value<T>& operator -=(U n) { return set(get() - n); }
template <typename U> inline byteswap_value<T>& operator *=(U n) { return set(get() * n); }
template <typename U> inline byteswap_value<T>& operator /=(U n) { return set(get() / n); }
template <typename U> inline byteswap_value<T>& operator %=(U n) { return set(get() % n); }
inline byteswap_value<T>& operator &=(T n) { return set(get() & n); }
inline byteswap_value<T>& operator |=(T n) { return set(get() | n); }
inline byteswap_value<T>& operator ^=(T n) { return set(get() ^ n); }
inline byteswap_value<T>& operator <<=(int n) { return set(get() << n); }
inline byteswap_value<T>& operator >>=(int n) { return set(get() >> n); }
protected:
inline T get() const { return native_cast(_v); }
inline byteswap_value<T>& set(T n) { _v = bswap_cast(n); return *this; }
};
テスト プログラム
endian-03.cpp (やや長いので折りたたみ)
#include "endian.hpp"
#include "byteswap.hpp"
// ----------------------------------------------------------------------------
#include <cstdint>
#include <limits>
#include <string>
/*
* byteswap_value
*/
template <typename T>
class byteswap_value
{
public:
typedef T value_type; // byteswap する native の型.
protected:
/* T が整数型時の情報 */
template <typename I>
struct integer_type
{
enum {
is_signed = std::numeric_limits<I>::is_signed,
bits = sizeof(I) * 8 - (is_signed ? 1 : 0),
};
typedef I type;
};
/* T が浮動小数点型時の情報 */
template <typename I, int B>
struct floating_type
{
enum { bits = B };
typedef I type;
};
/* 逆バイト順型 */
template <typename I> struct bswap : integer_type<I> {};
template <> struct bswap<float> : floating_type<std::uint32_t, 128> {};
template <> struct bswap<double> : floating_type<std::uint64_t, 1024> {};
typedef typename bswap<T>::type bswap_value; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline bswap_cast(const T& n) : v(n) {}
inline operator bswap_value() const
{ return std::byteswap(*(const bswap_value*)&v); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline native_cast(const bswap_value& s) : v(std::byteswap(s)) {}
inline operator T() const { return *(const T*)&v; }
};
protected:
/* 二項演算結果の型推定 */
template <typename U>
struct retval
{
template <typename V> struct chrint { typedef V type; };
template <> struct chrint<wchar_t> { typedef wint_t type; };
enum {
t_bits = bswap<T>::bits,
u_bits = bswap<U>::bits,
t_flag = t_bits > u_bits,
r_bits = t_flag ? t_bits : u_bits,
i_bits = bswap<int>::bits,
r_flag = r_bits > i_bits,
};
typedef typename std::conditional<t_flag, T, U>::type R;
typedef typename std::conditional<r_flag, R, int>::type V;
typedef typename chrint<V>::type type;
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
inline byteswap_value() {}
inline byteswap_value(T d) : _v(bswap_cast(d)) {}
inline byteswap_value(const byteswap_value<T>& s) : _v(s._v) {}
inline operator T() const { return get(); }
inline bool operator !() const { return !_v; }
inline bool operator ==(const byteswap_value<T>& s) const { return _v == s._v; }
inline bool operator !=(const byteswap_value<T>& s) const { return _v != s._v; }
template <typename U> inline bool operator < (U n) const { return get() < n; }
template <typename U> inline bool operator <=(U n) const { return get() <= n; }
template <typename U> inline bool operator ==(U n) const { return get() == n; }
template <typename U> inline bool operator !=(U n) const { return get() != n; }
template <typename U> inline bool operator >=(U n) const { return get() >= n; }
template <typename U> inline bool operator > (U n) const { return get() > n; }
inline T operator +() const { return +get(); }
inline T operator -() const { return -get(); }
inline T operator ~() const { return ~get(); }
template <typename U> inline typename retval<U>::type operator +(U n) const { return get() + n; }
template <typename U> inline typename retval<U>::type operator -(U n) const { return get() - n; }
template <typename U> inline typename retval<U>::type operator *(U n) const { return get() * n; }
template <typename U> inline typename retval<U>::type operator /(U n) const { return get() / n; }
template <typename U> inline typename retval<U>::type operator %(U n) const { return get() % n; }
template <typename U> inline typename retval<U>::type operator &(U n) const { return get() & n; }
template <typename U> inline typename retval<U>::type operator |(U n) const { return get() | n; }
template <typename U> inline typename retval<U>::type operator ^(U n) const { return get() ^ n; }
inline T operator <<(int n) const { return get() << n; }
inline T operator >>(int n) const { return get() >> n; }
inline byteswap_value<T>& operator =(T n) { return set(n); }
inline byteswap_value<T>& operator =(const byteswap_value<T>& s) { _v = s._v; return *this; }
template <typename U> inline byteswap_value<T>& operator +=(U n) { return set(get() + n); }
template <typename U> inline byteswap_value<T>& operator -=(U n) { return set(get() - n); }
template <typename U> inline byteswap_value<T>& operator *=(U n) { return set(get() * n); }
template <typename U> inline byteswap_value<T>& operator /=(U n) { return set(get() / n); }
template <typename U> inline byteswap_value<T>& operator %=(U n) { return set(get() % n); }
inline byteswap_value<T>& operator &=(T n) { return set(get() & n); }
inline byteswap_value<T>& operator |=(T n) { return set(get() | n); }
inline byteswap_value<T>& operator ^=(T n) { return set(get() ^ n); }
inline byteswap_value<T>& operator <<=(int n) { return set(get() << n); }
inline byteswap_value<T>& operator >>=(int n) { return set(get() >> n); }
protected:
inline T get() const { return native_cast(_v); }
inline byteswap_value<T>& set(T n) { _v = bswap_cast(n); return *this; }
};
// ----------------------------------------------------------------------------
#include <cstdint>
struct native_endian
{
enum {
is_big = std::endian::big == std::endian::native,
is_little = std::endian::little == std::endian::native,
};
typedef std::int8_t int8_type;
typedef std::int16_t int16_type;
typedef std::int32_t int32_type;
typedef std::int64_t int64_type;
typedef std::uint8_t uint8_type;
typedef std::uint16_t uint16_type;
typedef std::uint32_t uint32_type;
typedef std::uint64_t uint64_type;
typedef float float32_type;
typedef double float64_type;
typedef char char_type;
typedef wchar_t wchar_type;
};
struct byteswap_endian
{
enum {
is_big = !native_endian::is_big,
is_little = !native_endian::is_little,
};
typedef native_endian::int8_type int8_type;
typedef byteswap_value<native_endian::int16_type> int16_type;
typedef byteswap_value<native_endian::int32_type> int32_type;
typedef byteswap_value<native_endian::int64_type> int64_type;
typedef native_endian::uint8_type uint8_type;
typedef byteswap_value<native_endian::uint16_type> uint16_type;
typedef byteswap_value<native_endian::uint32_type> uint32_type;
typedef byteswap_value<native_endian::uint64_type> uint64_type;
typedef byteswap_value<native_endian::float32_type> float32_type;
typedef byteswap_value<native_endian::float64_type> float64_type;
typedef byteswap_value<native_endian::char_type> char_type;
typedef byteswap_value<native_endian::wchar_type> wchar_type;
};
template <bool big_endian>
struct fixed_endian : std::conditional<
big_endian == native_endian::is_big,
native_endian, byteswap_endian>::type {};
/* big endian */
typedef fixed_endian<true> big_endian;
typedef big_endian::int8_type int8be_t;
typedef big_endian::int16_type int16be_t;
typedef big_endian::int32_type int32be_t;
typedef big_endian::int64_type int64be_t;
typedef big_endian::uint8_type uint8be_t;
typedef big_endian::uint16_type uint16be_t;
typedef big_endian::uint32_type uint32be_t;
typedef big_endian::uint64_type uint64be_t;
typedef big_endian::float32_type float32be_t;
typedef big_endian::float64_type float64be_t;
typedef big_endian::char_type charbe_t;
typedef big_endian::wchar_type wcharbe_t;
/* little endian */
typedef fixed_endian<false> little_endian;
typedef little_endian::int8_type int8le_t;
typedef little_endian::int16_type int16le_t;
typedef little_endian::int32_type int32le_t;
typedef little_endian::int64_type int64le_t;
typedef little_endian::uint8_type uint8le_t;
typedef little_endian::uint16_type uint16le_t;
typedef little_endian::uint32_type uint32le_t;
typedef little_endian::uint64_type uint64le_t;
typedef little_endian::float32_type float32le_t;
typedef little_endian::float64_type float64le_t;
typedef little_endian::char_type charle_t;
typedef little_endian::wchar_type wcharle_t;
// ----------------------------------------------------------------------------
/*
* テスト
*/
#include <algorithm>
#include <cstdio>
#include <typeinfo>
#ifndef _countof
#define _countof(a) (sizeof(a) / sizeof(a[0]))
#endif
static const uint16_t native_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static uint16be_t big_data_u16[_countof(native_data_u16)];
static uint16le_t little_data_u16[_countof(native_data_u16)];
static const uint32_t native_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static uint32be_t big_data_u32[_countof(native_data_u32)];
static uint32le_t little_data_u32[_countof(native_data_u32)];
static const uint64_t native_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static uint64be_t big_data_u64[_countof(native_data_u64)];
static uint64le_t little_data_u64[_countof(native_data_u64)];
static const float native_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32be_t big_data_f32[_countof(native_data_f32)];
static float32le_t little_data_f32[_countof(native_data_f32)];
static const double native_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64be_t big_data_f64[_countof(native_data_f64)];
static float64le_t little_data_f64[_countof(native_data_f64)];
static void dumpbin(const char* msg, const void* s, size_t n)
{
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
size_t x, y, ny = n & ~15, nr = n & 15;
printf("address = %p: %s\n", s, msg);
for (y = 0; y < ny; y += 16)
{
printf(" ");
for (size_t x = 0; x < 16; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
if (y < n)
{
printf(" ");
for (x = 0; x < nr; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
}
template <typename T>
inline static void dumpbin(const char* msg, const T& s)
{
dumpbin(msg, &s, sizeof(T));
}
template <typename T>
inline static const char *gettypename()
{
return typeid(T()).name();
}
template <typename T>
inline static const char *gettypename(const T v)
{
return typeid(v).name();
}
template <typename T>
inline static const char *valuetypename()
{
return typeid(T(0)).name();
}
template <typename T>
static void rtypename(const char* name, const T& x)
{
int8_t i8 = 11;
int16_t i16 = 12;
int32_t i32 = 14;
int64_t i64 = 18;
uint8_t u8 = 21;
uint16_t u16 = 22;
uint32_t u32 = 24;
uint64_t u64 = 28;
float f32 = 1.5;
double f64 = 2.25;
char c8 = 1;
wchar_t wc = 2;
printf("%s = %s\n", name, gettypename(x));
printf(" +i8:%s +i16:%s +i32:%s +i64:%s\n",
gettypename(x + i8), gettypename(x + i16),
gettypename(x + i32), gettypename(x + i64));
printf(" +u8:%s +u16:%s +u32:%s +u64:%s\n",
gettypename(x + u8), gettypename(x + u16),
gettypename(x + u32), gettypename(x + u64));
printf(" +f32:%s +f64:%s\n",
gettypename(x + f32), gettypename(x + f64));
printf(" +char:%s +wchar:%s\n",
gettypename(x + c8), gettypename(x + wc));
printf("\n");
#if 0
T y = 0;
printf(" +=i8:%s +=i16:%s +=i32:%s +i64:%s\n",
gettypename(y += i8), gettypename(y += i16),
gettypename(y += i32), gettypename(y += i64));
printf(" +=u8:%s +=u16:%s +=u32:%s +=u64:%s\n",
gettypename(y += u8), gettypename(y += u16),
gettypename(y += u32), gettypename(y += u64));
printf(" +=f32:%s +=f64:%s\n",
gettypename(y += f32), gettypename(y += f64));
printf(" +=c8:%s +=wc:%s\n",
gettypename(y += c8), gettypename(y += wc));
printf("\n");
#endif
}
/*
*
*/
int main()
{
// big_data_XXX / little_data_XXX の初期化.
std::copy(native_data_u16, native_data_u16 + _countof(native_data_u16), big_data_u16);
std::copy(native_data_u16, native_data_u16 + _countof(native_data_u16), little_data_u16);
std::copy(native_data_u32, native_data_u32 + _countof(native_data_u32), big_data_u32);
std::copy(native_data_u32, native_data_u32 + _countof(native_data_u32), little_data_u32);
std::copy(native_data_u64, native_data_u64 + _countof(native_data_u64), big_data_u64);
std::copy(native_data_u64, native_data_u64 + _countof(native_data_u64), little_data_u64);
std::copy(native_data_f32, native_data_f32 + _countof(native_data_f32), big_data_f32);
std::copy(native_data_f32, native_data_f32 + _countof(native_data_f32), little_data_f32);
std::copy(native_data_f64, native_data_f64 + _countof(native_data_f64), big_data_f64);
std::copy(native_data_f64, native_data_f64 + _countof(native_data_f64), little_data_f64);
#ifdef __cplusplus
printf("compiler: __cplusplus = %ld\n", __cplusplus);
#endif
#ifdef _MSVC_LANG
printf("compiler: _MSVC_LANG = %ld\n", _MSVC_LANG);
#endif
printf("endian: native = %s\n", native_endian::is_big ? "big" : "little");
printf("\n");
dumpbin("native_data_u16", native_data_u16);
dumpbin("big_data_u16", big_data_u16);
dumpbin("little_data_u16", little_data_u16);
printf("\n");
dumpbin("native_data_u32", native_data_u32);
dumpbin("big_data_u32", big_data_u32);
dumpbin("little_data_u32", little_data_u32);
printf("\n");
dumpbin("native_data_u64", native_data_u64);
dumpbin("big_data_u64", big_data_u64);
dumpbin("little_data_u64", little_data_u64);
printf("\n");
dumpbin("native_data_f32", native_data_f32);
dumpbin("big_data_f32", big_data_f32);
dumpbin("little_data_f32", little_data_f32);
printf("\n");
dumpbin("native_data_f64", native_data_f64);
dumpbin("big_data_f64", big_data_f64);
dumpbin("little_data_f64", little_data_f64);
printf("\n");
int16be_t i16be = 32;
int32be_t i32be = 34;
int64be_t i64be = 38;
uint16be_t u16be = 42;
uint32be_t u32be = 44;
uint64be_t u64be = 48;
float32be_t f32be = 4.25;
float64be_t f64be = 8.125;
int16le_t i16le = i16be;
int32le_t i32le = i32be;
int64le_t i64le = i64be;
uint16le_t u16le = u16be;
uint32le_t u32le = u32be;
uint64le_t u64le = u64be;
float32le_t f32le = f32be;
float64le_t f64le = f64be;
/**/
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
dumpbin("float32be_t", f32be); dumpbin("float32le_t", f32le);
dumpbin("float64be_t", f64be); dumpbin("float64le_t", f64le);
printf("\n");
/**/
u16be = 32; u32be = 34; u64be = 38;
i16be = 42; i32be = 44; i64be = 48;
u16le = 32; u32le = 34; u64le = 38;
i16le = 42; i32le = 44; i64le = 48;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
u16be <<= 4; u32be <<= 4; u64be <<= 4;
i16be <<= 4; i32be <<= 4; i64be <<= 4;
u16le <<= 4; u32le <<= 4; u64le <<= 4;
i16le <<= 4; i32le <<= 4; i64le <<= 4;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
printf("compare:\n");
#define COMP(l,op,r) \
printf(" %s(%d) %-2s %s(%d) : %s\n", \
#l, (int)l, #op, #r, (int)r, \
(l op r) ? "true" : "false")
COMP(i16be, < , i16le); COMP(i16be, <=, i16le); COMP(i16be, ==, i16le);
COMP(i16be, !=, i16le); COMP(i16be, >=, i16le); COMP(i16be, > , i16le);
printf("\n");
COMP(i32be, < , i16le); COMP(i32be, <=, i16le); COMP(i32be, ==, i16le);
COMP(i32be, !=, i16le); COMP(i32be, >=, i16le); COMP(i32be, > , i16le);
printf("\n");
COMP(i32be, < , i64be); COMP(i32be, <=, i64be); COMP(i32be, ==, i64be);
COMP(i32be, !=, i64be); COMP(i32be, >=, i64be); COMP(i32be, > , i64be);
printf("\n");
COMP(i32be, < , i64le); COMP(i32be, <=, i64le); COMP(i32be, ==, i64le);
COMP(i32be, !=, i64le); COMP(i32be, >=, i64le); COMP(i32be, > , i64le);
printf("\n");
/**/
printf("typeid:\n");
printf(" int8_t:%s int16_t:%s int32_t:%s int64_t:%s\n",
valuetypename<int8_t>(), valuetypename<int16_t>(),
valuetypename<int32_t>(), valuetypename<int64_t>());
printf(" uint8_t:%s uint16_t:%s uint32_t:%s uint64_t:%s\n",
valuetypename<uint8_t>(), valuetypename<uint16_t>(),
valuetypename<uint32_t>(), valuetypename<uint64_t>());
printf(" float:%s double:%s\n", valuetypename<float>(), valuetypename<double>());
printf(" char:%s wchar_t:%s\n", valuetypename<char>(), valuetypename<wchar_t>());
printf(" int:%s unsigned:%s\n", valuetypename<int>(), valuetypename<unsigned>());
printf(" sizeof(wchar_t):%zd\n", sizeof(wchar_t));
printf("\n");
/**/
rtypename("int16be_t", i16be); rtypename("int16le_t", i16le);
rtypename("int32be_t", i32be); rtypename("int32le_t", i32le);
rtypename("int64be_t", i64be); rtypename("int64le_t", i64le);
rtypename("uint16be_t", u16be); rtypename("uint16le_t", u16le);
rtypename("uint32be_t", u32be); rtypename("uint32le_t", u32le);
rtypename("uint64be_t", u64be); rtypename("uint64le_t", u64le);
rtypename("float32be_t", f32be); rtypename("float32le_t", f32le);
rtypename("float64be_t", f64be); rtypename("float64le_t", f64le);
return 0;
}
$ clang++ -O3 -g0 -DNDEBUG=1 -std=c++03 endian-03.cpp -o endian-03
$ ./endian-03
compiler: __cplusplus = 199711
endian: native = little
address = 0x10c0eeaa0: native_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x10c0f0000: big_data_u16
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10c0f0060: little_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x10c0eeab0: native_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x10c0f0010: big_data_u32
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10c0f0070: little_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x10c0eeac0: native_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x10c0f0020: big_data_u64
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10c0f0080: little_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x10c0eead0: native_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x10c0f0030: big_data_f32
34 56 78 9a 45 67 89 ab 56 78 9a bc 76 54 32 10
address = 0x10c0f0090: little_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x10c0eeae0: native_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x10c0f0040: big_data_f64
34 56 78 9a bc de f0 12 45 67 89 ab cd ef 01 23
56 78 9a bc de f0 12 34 76 54 32 10 fe dc ba 98
address = 0x10c0f00a0: little_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x7ff7b3e14630: i16be_t
00 20
address = 0x7ff7b3e14636: i16le_t
20 00
address = 0x7ff7b3e14620: u16be_t
00 2a
address = 0x7ff7b3e1461e: u16le_t
2a 00
address = 0x7ff7b3e14628: i32be_t
00 00 00 22
address = 0x7ff7b3e14600: i32le_t
22 00 00 00
address = 0x7ff7b3e14618: u32be_t
00 00 00 2c
address = 0x7ff7b3e14604: u32le_t
2c 00 00 00
address = 0x7ff7b3e14610: i64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7b3e14608: i64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7b3e145f8: u64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7b3e145f0: u64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7b3e145e8: float32be_t
40 88 00 00
address = 0x7ff7b3e145e4: float32le_t
00 00 88 40
address = 0x7ff7b3e145d0: float64be_t
40 20 40 00 00 00 00 00
address = 0x7ff7b3e145d8: float64le_t
00 00 00 00 00 40 20 40
address = 0x7ff7b3e14630: i16be_t
00 2a
address = 0x7ff7b3e14636: i16le_t
2a 00
address = 0x7ff7b3e14620: u16be_t
00 20
address = 0x7ff7b3e1461e: u16le_t
20 00
address = 0x7ff7b3e14628: i32be_t
00 00 00 2c
address = 0x7ff7b3e14600: i32le_t
2c 00 00 00
address = 0x7ff7b3e14618: u32be_t
00 00 00 22
address = 0x7ff7b3e14604: u32le_t
22 00 00 00
address = 0x7ff7b3e14610: i64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7b3e14608: i64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7b3e145f8: u64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7b3e145f0: u64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7b3e14630: i16be_t
02 a0
address = 0x7ff7b3e14636: i16le_t
a0 02
address = 0x7ff7b3e14620: u16be_t
02 00
address = 0x7ff7b3e1461e: u16le_t
00 02
address = 0x7ff7b3e14628: i32be_t
00 00 02 c0
address = 0x7ff7b3e14600: i32le_t
c0 02 00 00
address = 0x7ff7b3e14618: u32be_t
00 00 02 20
address = 0x7ff7b3e14604: u32le_t
20 02 00 00
address = 0x7ff7b3e14610: i64be_t
00 00 00 00 00 00 03 00
address = 0x7ff7b3e14608: i64le_t
00 03 00 00 00 00 00 00
address = 0x7ff7b3e145f8: u64be_t
00 00 00 00 00 00 02 60
address = 0x7ff7b3e145f0: u64le_t
60 02 00 00 00 00 00 00
compare:
i16be(672) < i16le(672) : false
i16be(672) <= i16le(672) : true
i16be(672) == i16le(672) : true
i16be(672) != i16le(672) : false
i16be(672) >= i16le(672) : true
i16be(672) > i16le(672) : false
i32be(704) < i16le(672) : false
i32be(704) <= i16le(672) : false
i32be(704) == i16le(672) : false
i32be(704) != i16le(672) : true
i32be(704) >= i16le(672) : true
i32be(704) > i16le(672) : true
i32be(704) < i64be(768) : true
i32be(704) <= i64be(768) : true
i32be(704) == i64be(768) : false
i32be(704) != i64be(768) : true
i32be(704) >= i64be(768) : false
i32be(704) > i64be(768) : false
i32be(704) < i64le(768) : true
i32be(704) <= i64le(768) : true
i32be(704) == i64le(768) : false
i32be(704) != i64le(768) : true
i32be(704) >= i64le(768) : false
i32be(704) > i64le(768) : false
typeid:
int8_t:a int16_t:s int32_t:i int64_t:x
uint8_t:h uint16_t:t uint32_t:j uint64_t:y
float:f double:d
char:c wchar_t:w
int:i unsigned:j
sizeof(wchar_t):4
int16be_t = 14byteswap_valueIsE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+f32:f +f64:d
+char:i +wchar:i
int16le_t = s
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+f32:f +f64:d
+char:i +wchar:i
int32be_t = 14byteswap_valueIiE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+f32:f +f64:d
+char:i +wchar:i
int32le_t = i
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+f32:f +f64:d
+char:i +wchar:i
int64be_t = 14byteswap_valueIxE
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+f32:f +f64:d
+char:x +wchar:x
int64le_t = x
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+f32:f +f64:d
+char:x +wchar:x
uint16be_t = 14byteswap_valueItE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+f32:f +f64:d
+char:i +wchar:i
uint16le_t = t
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+f32:f +f64:d
+char:i +wchar:i
uint32be_t = 14byteswap_valueIjE
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+f32:f +f64:d
+char:j +wchar:j
uint32le_t = j
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+f32:f +f64:d
+char:j +wchar:j
uint64be_t = 14byteswap_valueIyE
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+f32:f +f64:d
+char:y +wchar:y
uint64le_t = y
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+f32:f +f64:d
+char:y +wchar:y
float32be_t = 14byteswap_valueIfE
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+f32:f +f64:d
+char:f +wchar:f
float32le_t = f
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+f32:f +f64:d
+char:f +wchar:f
float64be_t = 14byteswap_valueIdE
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+f32:d +f64:d
+char:d +wchar:d
float64le_t = d
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+f32:d +f64:d
+char:d +wchar:d
C++11 で書いてみる
template <typename T>
class byteswap_value
{
public:
using value_type = T; // byteswap する native の型.
protected:
/* 逆バイト順型 */
template <typename I> struct bswap { using type = I; };
template <> struct bswap<float> { using type = std::uint32_t; };
template <> struct bswap<double> { using type = std::uint64_t; };
using bswap_value = typename bswap<T>::type; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline constexpr bswap_cast(const T& n) noexcept : v(n) {}
inline constexpr operator bswap_value() const noexcept
{ return std::byteswap(*(const bswap_value*)&v); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline constexpr native_cast(const bswap_value& s) noexcept : v(std::byteswap(s)) {}
inline constexpr operator T() const noexcept { return *(const T*)&v; }
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
byteswap_value() noexcept = default;
inline constexpr byteswap_value(T d) noexcept : _v(bswap_cast(d)) {}
constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
inline constexpr operator T() const noexcept { return get(); }
inline constexpr bool operator !() const noexcept { return !_v; }
inline constexpr bool operator ==(const byteswap_value<T>& s) const noexcept { return _v == s._v; }
inline constexpr bool operator !=(const byteswap_value<T>& s) const noexcept { return _v != s._v; }
template <typename U> inline constexpr bool operator < (U n) const noexcept { return get() < n; }
template <typename U> inline constexpr bool operator <=(U n) const noexcept { return get() <= n; }
template <typename U> inline constexpr bool operator ==(U n) const noexcept { return get() == n; }
template <typename U> inline constexpr bool operator !=(U n) const noexcept { return get() != n; }
template <typename U> inline constexpr bool operator >=(U n) const noexcept { return get() >= n; }
template <typename U> inline constexpr bool operator > (U n) const noexcept { return get() > n; }
inline constexpr T operator +() const noexcept { return +get(); }
inline constexpr T operator -() const noexcept { return -get(); }
inline constexpr T operator ~() const noexcept { return ~get(); }
template <typename U> inline constexpr decltype(T() + U()) operator +(U n) const noexcept { return get() + n; }
template <typename U> inline constexpr decltype(T() - U()) operator -(U n) const noexcept { return get() - n; }
template <typename U> inline constexpr decltype(T() * U()) operator *(U n) const noexcept { return get() * n; }
template <typename U> inline constexpr decltype(T() / U()) operator /(U n) const noexcept { return get() / n; }
template <typename U> inline constexpr decltype(T() % U()) operator %(U n) const noexcept { return get() % n; }
template <typename U> inline constexpr decltype(T() & U()) operator &(U n) const noexcept { return get() & n; }
template <typename U> inline constexpr decltype(T() | U()) operator |(U n) const noexcept { return get() | n; }
template <typename U> inline constexpr decltype(T() ^ U()) operator ^(U n) const noexcept { return get() ^ n; }
inline constexpr T operator <<(int n) const noexcept { return get() << n; }
inline constexpr T operator >>(int n) const noexcept { return get() >> n; }
inline byteswap_value<T>& operator =(T n) { return set(n); }
byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
template <typename U> inline byteswap_value<T>& operator +=(U n) noexcept { return set(get() + n); }
template <typename U> inline byteswap_value<T>& operator -=(U n) noexcept { return set(get() - n); }
template <typename U> inline byteswap_value<T>& operator *=(U n) noexcept { return set(get() * n); }
template <typename U> inline byteswap_value<T>& operator /=(U n) noexcept { return set(get() / n); }
template <typename U> inline byteswap_value<T>& operator %=(U n) noexcept { return set(get() % n); }
inline byteswap_value<T>& operator &=(T n) noexcept { return set(get() & n); }
inline byteswap_value<T>& operator |=(T n) noexcept { return set(get() | n); }
inline byteswap_value<T>& operator ^=(T n) noexcept { return set(get() ^ n); }
inline byteswap_value<T>& operator <<=(int n) noexcept { return set(get() << n); }
inline byteswap_value<T>& operator >>=(int n) noexcept { return set(get() >> n); }
protected:
inline constexpr T get() const noexcept { return native_cast(_v); }
inline byteswap_value<T>& set(T n) noexcept { _v = bswap_cast(n); return *this; }
};
C++03 からの変更
trivial 型になった
- コンストラクタとコピー代入演算子を
= default
に変更。
- inline byteswap_value() {}
- inline byteswap_value(const byteswap_value<T>& s) : _v(s._v) {}
- inline byteswap_value<T>& operator =(const byteswap_value<T>& s) { _v = s._v; return *this; }
+ byteswap_value() noexcept = default;
+ constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
+ byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
演算子の返り値型を decltyle
で置換
- template <typename U> inline typename retval<U>::type operator +(U n) const { return get() + n; }
+ template <typename U> inline constexpr decltype(T() + U()) operator +(U n) const noexcept { return get() + n; }
加えて、自前の型推論の関連記述を削除。
constexpr 修飾子の使用
constexpr
のメンバ関数にconst
を付けられないらしいが、const
を外してclang++ -std=c++11
でコンパイルすると警告が出るので付けておく。
warning: 'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior [-Wconstexpr-not-const]
最適化するとエンディアン値が直接配置される
最適化しないとコンストラクタが呼ばれるが、最適化して値が確定する場合はコンストラクタが呼ばれず直接配置してくれる。
static const uint32_t native_data_u32[] = { 0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210 };
static const uint32be_t big_data_u32[] = { 0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210 };
static const uint32le_t little_data_u32[] = { 0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210 };
__ZL15native_data_u32:
.long 19088743 ## 0x1234567
.long 2309737967 ## 0x89abcdef
.long 4275878552 ## 0xfedcba98
.long 1985229328 ## 0x76543210
〜〜〜(略)〜〜〜
__ZL12big_data_u32:
.long 1732584193 ## 0x67452301
.long 4023233417 ## 0xefcdab89
.long 2562383102 ## 0x98badcfe
.long 271733878 ## 0x10325476
〜〜〜(略)〜〜〜
__ZL15little_data_u32:
.long 19088743 ## 0x1234567
.long 2309737967 ## 0x89abcdef
.long 4275878552 ## 0xfedcba98
.long 1985229328 ## 0x76543210
std::basic_string が利用可能
using wstringbe = std::basic_string<wcharbe_t>;
using wstringle = std::basic_string<wcharle_t>;
using u16stringbe = std::basic_string<char16be_t>;
using u16stringle = std::basic_string<char16le_t>;
using u32stringbe = std::basic_string<char32be_t>;
using u32stringle = std::basic_string<char32le_t>;
サロゲートペア文字の変換は行われませんが
std::wstring ws(L"サンプルTEXT"); // UTF-16/32
u16stringbe u16sbe(u16s.begin(), u16s.end()); // UTF-16BE
u16stringle u16sle(u16s.begin(), u16s.end()); // UTF-16LE
とすることができます。
その他
-
typedef
からusing
に変更 -
noexcept
修飾を使用 -
char16_t, char32_t
に対する定義を追加(各エンディアン型)
テスト プログラム
endian-11.cpp (やや長いので折りたたみ)
#include "endian.hpp"
#include "byteswap.hpp"
// ----------------------------------------------------------------------------
#include <cstdint>
#include <limits>
/*
* byteswap_value
*/
template <typename T>
class byteswap_value
{
public:
using value_type = T; // byteswap する native の型.
protected:
/* 逆バイト順型 */
template <typename I> struct bswap { using type = I; };
template <> struct bswap<float> { using type = std::uint32_t; };
template <> struct bswap<double> { using type = std::uint64_t; };
using bswap_value = typename bswap<T>::type; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline constexpr bswap_cast(const T& n) noexcept : v(n) {}
inline constexpr operator bswap_value() const noexcept
{ return std::byteswap(*(const bswap_value*)&v); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline constexpr native_cast(const bswap_value& s) noexcept : v(std::byteswap(s)) {}
inline constexpr operator T() const noexcept { return *(const T*)&v; }
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
byteswap_value() noexcept = default;
inline constexpr byteswap_value(T d) noexcept : _v(bswap_cast(d)) {}
constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
inline constexpr operator T() const noexcept { return get(); }
inline constexpr bool operator !() const noexcept { return !_v; }
inline constexpr bool operator ==(const byteswap_value<T>& s) const noexcept { return _v == s._v; }
inline constexpr bool operator !=(const byteswap_value<T>& s) const noexcept { return _v != s._v; }
template <typename U> inline constexpr bool operator < (U n) const noexcept { return get() < n; }
template <typename U> inline constexpr bool operator <=(U n) const noexcept { return get() <= n; }
template <typename U> inline constexpr bool operator ==(U n) const noexcept { return get() == n; }
template <typename U> inline constexpr bool operator !=(U n) const noexcept { return get() != n; }
template <typename U> inline constexpr bool operator >=(U n) const noexcept { return get() >= n; }
template <typename U> inline constexpr bool operator > (U n) const noexcept { return get() > n; }
inline constexpr T operator +() const noexcept { return +get(); }
inline constexpr T operator -() const noexcept { return -get(); }
inline constexpr T operator ~() const noexcept { return ~get(); }
template <typename U> inline constexpr decltype(T() + U()) operator +(U n) const noexcept { return get() + n; }
template <typename U> inline constexpr decltype(T() - U()) operator -(U n) const noexcept { return get() - n; }
template <typename U> inline constexpr decltype(T() * U()) operator *(U n) const noexcept { return get() * n; }
template <typename U> inline constexpr decltype(T() / U()) operator /(U n) const noexcept { return get() / n; }
template <typename U> inline constexpr decltype(T() % U()) operator %(U n) const noexcept { return get() % n; }
template <typename U> inline constexpr decltype(T() & U()) operator &(U n) const noexcept { return get() & n; }
template <typename U> inline constexpr decltype(T() | U()) operator |(U n) const noexcept { return get() | n; }
template <typename U> inline constexpr decltype(T() ^ U()) operator ^(U n) const noexcept { return get() ^ n; }
inline constexpr T operator <<(int n) const noexcept { return get() << n; }
inline constexpr T operator >>(int n) const noexcept { return get() >> n; }
inline byteswap_value<T>& operator =(T n) { return set(n); }
byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
template <typename U> inline byteswap_value<T>& operator +=(U n) noexcept { return set(get() + n); }
template <typename U> inline byteswap_value<T>& operator -=(U n) noexcept { return set(get() - n); }
template <typename U> inline byteswap_value<T>& operator *=(U n) noexcept { return set(get() * n); }
template <typename U> inline byteswap_value<T>& operator /=(U n) noexcept { return set(get() / n); }
template <typename U> inline byteswap_value<T>& operator %=(U n) noexcept { return set(get() % n); }
inline byteswap_value<T>& operator &=(T n) noexcept { return set(get() & n); }
inline byteswap_value<T>& operator |=(T n) noexcept { return set(get() | n); }
inline byteswap_value<T>& operator ^=(T n) noexcept { return set(get() ^ n); }
inline byteswap_value<T>& operator <<=(int n) noexcept { return set(get() << n); }
inline byteswap_value<T>& operator >>=(int n) noexcept { return set(get() >> n); }
protected:
inline constexpr T get() const noexcept { return native_cast(_v); }
inline byteswap_value<T>& set(T n) noexcept { _v = bswap_cast(n); return *this; }
};
// ----------------------------------------------------------------------------
#include <string>
struct native_endian
{
enum {
is_big = std::endian::big == std::endian::native,
is_little = std::endian::little == std::endian::native,
};
using int8_type = std::int8_t;
using int16_type = std::int16_t;
using int32_type = std::int32_t;
using int64_type = std::int64_t;
using uint8_type = std::uint8_t;
using uint16_type = std::uint16_t;
using uint32_type = std::uint32_t;
using uint64_type = std::uint64_t;
using float32_type = float;
using float64_type = double;
using char_type = char;
using wchar_type = wchar_t;
using char16_type = char16_t;
using char32_type = char32_t;
};
struct byteswap_endian
{
enum {
is_big = !native_endian::is_big,
is_little = !native_endian::is_little,
};
using int8_type = native_endian::int8_type;
using int16_type = byteswap_value<native_endian::int16_type>;
using int32_type = byteswap_value<native_endian::int32_type>;
using int64_type = byteswap_value<native_endian::int64_type>;
using uint8_type = native_endian::uint8_type;
using uint16_type = byteswap_value<native_endian::uint16_type>;
using uint32_type = byteswap_value<native_endian::uint32_type>;
using uint64_type = byteswap_value<native_endian::uint64_type>;
using float32_type = byteswap_value<native_endian::float32_type>;
using float64_type = byteswap_value<native_endian::float64_type>;
using char_type = byteswap_value<native_endian::char_type>;
using wchar_type = byteswap_value<native_endian::wchar_type>;
using char16_type = byteswap_value<native_endian::char16_type>;
using char32_type = byteswap_value<native_endian::char32_type>;
};
template <bool big>
using fixed_endian = typename std::conditional<
big == native_endian::is_big, native_endian, byteswap_endian>::type;
/* big endian */
using big_endian = fixed_endian<true>;
using int8be_t = big_endian::int8_type;
using int16be_t = big_endian::int16_type;
using int32be_t = big_endian::int32_type;
using int64be_t = big_endian::int64_type;
using uint8be_t = big_endian::uint8_type;
using uint16be_t = big_endian::uint16_type;
using uint32be_t = big_endian::uint32_type;
using uint64be_t = big_endian::uint64_type;
using float32be_t = big_endian::float32_type;
using float64be_t = big_endian::float64_type;
using charbe_t = big_endian::char_type;
using wcharbe_t = big_endian::wchar_type;
using char16be_t = big_endian::char16_type;
using char32be_t = big_endian::char32_type;
using stringbe = std::basic_string<charbe_t>;
using wstringbe = std::basic_string<wcharbe_t>;
using u16stringbe = std::basic_string<char16be_t>;
using u32stringbe = std::basic_string<char32be_t>;
/* little endian */
using little_endian = fixed_endian<false>;
using int8le_t = little_endian::int8_type;
using int16le_t = little_endian::int16_type;
using int32le_t = little_endian::int32_type;
using int64le_t = little_endian::int64_type;
using uint8le_t = little_endian::uint8_type;
using uint16le_t = little_endian::uint16_type;
using uint32le_t = little_endian::uint32_type;
using uint64le_t = little_endian::uint64_type;
using float32le_t = little_endian::float32_type;
using float64le_t = little_endian::float64_type;
using charle_t = little_endian::char_type;
using wcharle_t = little_endian::wchar_type;
using char16le_t = little_endian::char16_type;
using char32le_t = little_endian::char32_type;
using stringle = std::basic_string<charle_t>;
using wstringle = std::basic_string<wcharle_t>;
using u16stringle = std::basic_string<char16le_t>;
using u32stringle = std::basic_string<char32le_t>;
// ----------------------------------------------------------------------------
/*
* テスト
*/
#include <algorithm>
#include <cstdio>
#include <typeinfo>
static const uint16_t native_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint16be_t big_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint16le_t little_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint32_t native_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint32be_t big_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint32le_t little_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint64_t native_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const uint64be_t big_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const uint64le_t little_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const float native_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32be_t big_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32le_t little_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static const double native_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64be_t big_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64le_t little_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static void dumpbin(const char* msg, const void* s, size_t n)
{
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
size_t x, y, ny = n & ~15, nr = n & 15;
printf("address = %p: %s\n", s, msg);
for (y = 0; y < ny; y += 16)
{
printf(" ");
for (size_t x = 0; x < 16; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
if (y < n)
{
printf(" ");
for (x = 0; x < nr; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
}
template <typename T>
inline static void dumpbin(const char* msg, const T& s)
{
dumpbin(msg, &s, sizeof(T));
}
template <typename T>
inline static void dumpbin(const char* msg, const std::basic_string<T>& s)
{
dumpbin(msg, s.data(), s.size() * sizeof(T));
}
template <typename T>
inline static const char *gettypename()
{
return typeid(T()).name();
}
template <typename T>
inline static const char *gettypename(const T v)
{
return typeid(v).name();
}
template <typename T>
inline static const char *valuetypename()
{
return typeid(T(0)).name();
}
template <typename T>
static void rtypename(const char* name, const T& x)
{
int8_t i8 = 11;
int16_t i16 = 12;
int32_t i32 = 14;
int64_t i64 = 18;
uint8_t u8 = 21;
uint16_t u16 = 22;
uint32_t u32 = 24;
uint64_t u64 = 28;
float f32 = 1.5;
double f64 = 2.25;
char c8 = 1;
wchar_t wc = 2;
char16_t c16 = 2;
char32_t c32 = 4;
printf("%s = %s\n", name, gettypename(x));
printf(" +i8:%s +i16:%s +i32:%s +i64:%s\n",
gettypename(x + i8), gettypename(x + i16),
gettypename(x + i32), gettypename(x + i64));
printf(" +u8:%s +u16:%s +u32:%s +u64:%s\n",
gettypename(x + u8), gettypename(x + u16),
gettypename(x + u32), gettypename(x + u64));
printf(" +c8:%s +c16:%s +c32:%s +wc:%s\n",
gettypename(x + c8), gettypename(x + c16),
gettypename(x + c32), gettypename(x + wc));
printf(" +f32:%s +f64:%s\n",
gettypename(x + f32), gettypename(x + f64));
printf("\n");
#if 0
T y = 0;
printf(" +=i8:%s +=i16:%s +=i32:%s +i64:%s\n",
gettypename(y += i8), gettypename(y += i16),
gettypename(y += i32), gettypename(y += i64));
printf(" +=u8:%s +=u16:%s +=u32:%s +=u64:%s\n",
gettypename(y += u8), gettypename(y += u16),
gettypename(y += u32), gettypename(y += u64));
printf(" +=f32:%s +=f64:%s\n",
gettypename(y += f32), gettypename(y += f64));
printf(" +=c8:%s +=wc:%s\n",
gettypename(y += c8), gettypename(y += wc));
printf("\n");
#endif
}
/*
*
*/
int main()
{
#ifdef __cplusplus
printf("compiler: __cplusplus = %ld\n", __cplusplus);
#endif
#ifdef _MSVC_LANG
printf("compiler: _MSVC_LANG = %ld\n", _MSVC_LANG);
#endif
printf("endian: native = %s\n", native_endian::is_big ? "big" : "little");
printf("\n");
dumpbin("native_data_u16", native_data_u16);
dumpbin("big_data_u16", big_data_u16);
dumpbin("little_data_u16", little_data_u16);
printf("\n");
dumpbin("native_data_u32", native_data_u32);
dumpbin("big_data_u32", big_data_u32);
dumpbin("little_data_u32", little_data_u32);
printf("\n");
dumpbin("native_data_u64", native_data_u64);
dumpbin("big_data_u64", big_data_u64);
dumpbin("little_data_u64", little_data_u64);
printf("\n");
dumpbin("native_data_f32", native_data_f32);
dumpbin("big_data_f32", big_data_f32);
dumpbin("little_data_f32", little_data_f32);
printf("\n");
dumpbin("native_data_f64", native_data_f64);
dumpbin("big_data_f64", big_data_f64);
dumpbin("little_data_f64", little_data_f64);
printf("\n");
int16be_t i16be = 32;
int32be_t i32be = 34;
int64be_t i64be = 38;
uint16be_t u16be = 42;
uint32be_t u32be = 44;
uint64be_t u64be = 48;
float32be_t f32be = 4.25;
float64be_t f64be = 8.125;
int16le_t i16le = i16be;
int32le_t i32le = i32be;
int64le_t i64le = i64be;
uint16le_t u16le = u16be;
uint32le_t u32le = u32be;
uint64le_t u64le = u64be;
float32le_t f32le = f32be;
float64le_t f64le = f64be;
/**/
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
dumpbin("float32be_t", f32be); dumpbin("float32le_t", f32le);
dumpbin("float64be_t", f64be); dumpbin("float64le_t", f64le);
printf("\n");
/**/
u16be = 32; u32be = 34; u64be = 38;
i16be = 42; i32be = 44; i64be = 48;
u16le = 32; u32le = 34; u64le = 38;
i16le = 42; i32le = 44; i64le = 48;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
u16be <<= 4; u32be <<= 4; u64be <<= 4;
i16be <<= 4; i32be <<= 4; i64be <<= 4;
u16le <<= 4; u32le <<= 4; u64le <<= 4;
i16le <<= 4; i32le <<= 4; i64le <<= 4;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
printf("compare:\n");
#define COMP(l,op,r) \
printf(" %s(%d) %-2s %s(%d) : %s\n", \
#l, (int)l, #op, #r, (int)r, \
(l op r) ? "true" : "false")
COMP(i16be, < , i16le); COMP(i16be, <=, i16le); COMP(i16be, ==, i16le);
COMP(i16be, !=, i16le); COMP(i16be, >=, i16le); COMP(i16be, > , i16le);
printf("\n");
COMP(i32be, < , i16le); COMP(i32be, <=, i16le); COMP(i32be, ==, i16le);
COMP(i32be, !=, i16le); COMP(i32be, >=, i16le); COMP(i32be, > , i16le);
printf("\n");
COMP(i32be, < , i64be); COMP(i32be, <=, i64be); COMP(i32be, ==, i64be);
COMP(i32be, !=, i64be); COMP(i32be, >=, i64be); COMP(i32be, > , i64be);
printf("\n");
COMP(i32be, < , i64le); COMP(i32be, <=, i64le); COMP(i32be, ==, i64le);
COMP(i32be, !=, i64le); COMP(i32be, >=, i64le); COMP(i32be, > , i64le);
printf("\n");
/**/
printf("typeid:\n");
printf(" int8_t:%s int16_t:%s int32_t:%s int64_t:%s\n",
valuetypename<int8_t>(), valuetypename<int16_t>(),
valuetypename<int32_t>(), valuetypename<int64_t>());
printf(" uint8_t:%s uint16_t:%s uint32_t:%s uint64_t:%s\n",
valuetypename<uint8_t>(), valuetypename<uint16_t>(),
valuetypename<uint32_t>(), valuetypename<uint64_t>());
printf(" float:%s double:%s\n", valuetypename<float>(), valuetypename<double>());
printf(" char:%s wchar_t:%s\n", valuetypename<char>(), valuetypename<wchar_t>());
printf(" int:%s unsigned:%s\n", valuetypename<int>(), valuetypename<unsigned>());
printf(" sizeof(wchar_t):%zd\n", sizeof(wchar_t));
printf("\n");
/**/
rtypename("int16be_t", i16be); rtypename("int16le_t", i16le);
rtypename("int32be_t", i32be); rtypename("int32le_t", i32le);
rtypename("int64be_t", i64be); rtypename("int64le_t", i64le);
rtypename("uint16be_t", u16be); rtypename("uint16le_t", u16le);
rtypename("uint32be_t", u32be); rtypename("uint32le_t", u32le);
rtypename("uint64be_t", u64be); rtypename("uint64le_t", u64le);
rtypename("float32be_t", f32be); rtypename("float32le_t", f32le);
rtypename("float64be_t", f64be); rtypename("float64le_t", f64le);
/**/
std::wstring ws(L"サンプルTEXT");
wstringbe wsbe(ws.begin(), ws.end());
wstringle wsle(ws.begin(), ws.end());
dumpbin("wstring", ws);
dumpbin("wstringbe", wsbe);
dumpbin("wstringle", wsle);
printf("\n");
std::u16string u16s(ws.begin(), ws.end()); /* sizeof(wchar_t) != sizeof(char16_t) の場合は要注意 */
u16stringbe u16sbe(u16s.begin(), u16s.end());
u16stringle u16sle(u16s.begin(), u16s.end());
dumpbin("u16string", u16s);
dumpbin("u16stringbe", u16sbe);
dumpbin("u16stringle", u16sle);
printf("\n");
std::u32string u32s(ws.begin(), ws.end()); /* sizeof(wchar_t) != sizeof(char32_t) の場合は要注意 */
u32stringbe u32sbe(u32s.begin(), u32s.end());
u32stringle u32sle(u32s.begin(), u32s.end());
dumpbin("u32string", u32s);
dumpbin("u32stringbe", u32sbe);
dumpbin("u32stringle", u32sle);
printf("\n");
return 0;
}
$ clang++ -O3 -g0 -DNDEBUG=1 -std=c++11 endian-11.cpp -o endian-11
$ ./endian-11
compiler: __cplusplus = 201103
endian: native = little
address = 0x10f5c2900: native_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x10f5c2910: big_data_u16
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10f5c2920: little_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x10f5c2930: native_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x10f5c2940: big_data_u32
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10f5c2950: little_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x10f5c2960: native_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x10f5c2970: big_data_u64
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10f5c2980: little_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x10f5c2990: native_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x10f5c4000: big_data_f32
34 56 78 9a 45 67 89 ab 56 78 9a bc 76 54 32 10
address = 0x10f5c4030: little_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x10f5c29a0: native_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x10f5c4010: big_data_f64
34 56 78 9a bc de f0 12 45 67 89 ab cd ef 01 23
56 78 9a bc de f0 12 34 76 54 32 10 fe dc ba 98
address = 0x10f5c4040: little_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x7ff7b0941630: i16be_t
00 20
address = 0x7ff7b0941636: i16le_t
20 00
address = 0x7ff7b0941620: u16be_t
00 2a
address = 0x7ff7b094161e: u16le_t
2a 00
address = 0x7ff7b0941628: i32be_t
00 00 00 22
address = 0x7ff7b0941600: i32le_t
22 00 00 00
address = 0x7ff7b0941618: u32be_t
00 00 00 2c
address = 0x7ff7b0941604: u32le_t
2c 00 00 00
address = 0x7ff7b0941610: i64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7b0941608: i64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7b09415f8: u64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7b09415f0: u64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7b09415e8: float32be_t
40 88 00 00
address = 0x7ff7b09415e4: float32le_t
00 00 88 40
address = 0x7ff7b09415d0: float64be_t
40 20 40 00 00 00 00 00
address = 0x7ff7b09415d8: float64le_t
00 00 00 00 00 40 20 40
address = 0x7ff7b0941630: i16be_t
00 2a
address = 0x7ff7b0941636: i16le_t
2a 00
address = 0x7ff7b0941620: u16be_t
00 20
address = 0x7ff7b094161e: u16le_t
20 00
address = 0x7ff7b0941628: i32be_t
00 00 00 2c
address = 0x7ff7b0941600: i32le_t
2c 00 00 00
address = 0x7ff7b0941618: u32be_t
00 00 00 22
address = 0x7ff7b0941604: u32le_t
22 00 00 00
address = 0x7ff7b0941610: i64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7b0941608: i64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7b09415f8: u64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7b09415f0: u64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7b0941630: i16be_t
02 a0
address = 0x7ff7b0941636: i16le_t
a0 02
address = 0x7ff7b0941620: u16be_t
02 00
address = 0x7ff7b094161e: u16le_t
00 02
address = 0x7ff7b0941628: i32be_t
00 00 02 c0
address = 0x7ff7b0941600: i32le_t
c0 02 00 00
address = 0x7ff7b0941618: u32be_t
00 00 02 20
address = 0x7ff7b0941604: u32le_t
20 02 00 00
address = 0x7ff7b0941610: i64be_t
00 00 00 00 00 00 03 00
address = 0x7ff7b0941608: i64le_t
00 03 00 00 00 00 00 00
address = 0x7ff7b09415f8: u64be_t
00 00 00 00 00 00 02 60
address = 0x7ff7b09415f0: u64le_t
60 02 00 00 00 00 00 00
compare:
i16be(672) < i16le(672) : false
i16be(672) <= i16le(672) : true
i16be(672) == i16le(672) : true
i16be(672) != i16le(672) : false
i16be(672) >= i16le(672) : true
i16be(672) > i16le(672) : false
i32be(704) < i16le(672) : false
i32be(704) <= i16le(672) : false
i32be(704) == i16le(672) : false
i32be(704) != i16le(672) : true
i32be(704) >= i16le(672) : true
i32be(704) > i16le(672) : true
i32be(704) < i64be(768) : true
i32be(704) <= i64be(768) : true
i32be(704) == i64be(768) : false
i32be(704) != i64be(768) : true
i32be(704) >= i64be(768) : false
i32be(704) > i64be(768) : false
i32be(704) < i64le(768) : true
i32be(704) <= i64le(768) : true
i32be(704) == i64le(768) : false
i32be(704) != i64le(768) : true
i32be(704) >= i64le(768) : false
i32be(704) > i64le(768) : false
typeid:
int8_t:a int16_t:s int32_t:i int64_t:x
uint8_t:h uint16_t:t uint32_t:j uint64_t:y
float:f double:d
char:c wchar_t:w
int:i unsigned:j
sizeof(wchar_t):4
int16be_t = 14byteswap_valueIsE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int16le_t = s
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int32be_t = 14byteswap_valueIiE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int32le_t = i
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int64be_t = 14byteswap_valueIxE
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+c8:x +c16:x +c32:x +wc:x
+f32:f +f64:d
int64le_t = x
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+c8:x +c16:x +c32:x +wc:x
+f32:f +f64:d
uint16be_t = 14byteswap_valueItE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
uint16le_t = t
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
uint32be_t = 14byteswap_valueIjE
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+c8:j +c16:j +c32:j +wc:j
+f32:f +f64:d
uint32le_t = j
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+c8:j +c16:j +c32:j +wc:j
+f32:f +f64:d
uint64be_t = 14byteswap_valueIyE
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+c8:y +c16:y +c32:y +wc:y
+f32:f +f64:d
uint64le_t = y
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+c8:y +c16:y +c32:y +wc:y
+f32:f +f64:d
float32be_t = 14byteswap_valueIfE
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+c8:f +c16:f +c32:f +wc:f
+f32:f +f64:d
float32le_t = f
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+c8:f +c16:f +c32:f +wc:f
+f32:f +f64:d
float64be_t = 14byteswap_valueIdE
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+c8:d +c16:d +c32:d +wc:d
+f32:d +f64:d
float64le_t = d
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+c8:d +c16:d +c32:d +wc:d
+f32:d +f64:d
address = 0x600001cbc000: wstring
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x600001cbc030: wstringbe
00 00 30 b5 00 00 30 f3 00 00 30 d7 00 00 30 eb
00 00 00 54 00 00 00 45 00 00 00 58 00 00 00 54
address = 0x600001cbc060: wstringle
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x7ff7b094159a: u16string
b5 30 f3 30 d7 30 eb 30 54 00 45 00 58 00 54 00
address = 0x7ff7b0941552: u16stringbe
30 b5 30 f3 30 d7 30 eb 00 54 00 45 00 58 00 54
address = 0x7ff7b094156a: u16stringle
b5 30 f3 30 d7 30 eb 30 54 00 45 00 58 00 54 00
address = 0x600001cb0000: u32string
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x600001cb0030: u32stringbe
00 00 30 b5 00 00 30 f3 00 00 30 d7 00 00 30 eb
00 00 00 54 00 00 00 45 00 00 00 58 00 00 00 54
address = 0x600001cb0060: u32stringle
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
C++14 で書いてみる
template <typename T>
class byteswap_value
{
public:
using value_type = T; // byteswap する native の型.
protected:
/* 逆バイト順型 */
template <typename I> struct bswap { using type = I; };
template <> struct bswap<float> { using type = std::uint32_t; };
template <> struct bswap<double> { using type = std::uint64_t; };
using bswap_value = typename bswap<T>::type; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline constexpr bswap_cast(const T& n) noexcept : v(n) {}
inline constexpr operator bswap_value() const noexcept
{ return std::byteswap(*(const bswap_value*)&v); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline constexpr native_cast(const bswap_value& s) noexcept : v(std::byteswap(s)) {}
inline constexpr operator T() const noexcept { return *(const T*)&v; }
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
byteswap_value() noexcept = default;
inline constexpr byteswap_value(T d) noexcept : _v(bswap_cast(d)) {}
constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
inline constexpr operator T() const noexcept { return get(); }
inline constexpr bool operator !() const noexcept { return !_v; }
inline constexpr bool operator ==(const byteswap_value<T>& s) const noexcept { return _v == s._v; }
inline constexpr bool operator !=(const byteswap_value<T>& s) const noexcept { return _v != s._v; }
template <typename U> inline constexpr bool operator < (U n) const noexcept { return get() < n; }
template <typename U> inline constexpr bool operator <=(U n) const noexcept { return get() <= n; }
template <typename U> inline constexpr bool operator ==(U n) const noexcept { return get() == n; }
template <typename U> inline constexpr bool operator !=(U n) const noexcept { return get() != n; }
template <typename U> inline constexpr bool operator >=(U n) const noexcept { return get() >= n; }
template <typename U> inline constexpr bool operator > (U n) const noexcept { return get() > n; }
inline constexpr T operator +() const noexcept { return +get(); }
inline constexpr T operator -() const noexcept { return -get(); }
inline constexpr T operator ~() const noexcept { return ~get(); }
template <typename U> inline constexpr auto operator +(U n) const noexcept { return get() + n; }
template <typename U> inline constexpr auto operator -(U n) const noexcept { return get() - n; }
template <typename U> inline constexpr auto operator *(U n) const noexcept { return get() * n; }
template <typename U> inline constexpr auto operator /(U n) const noexcept { return get() / n; }
template <typename U> inline constexpr auto operator %(U n) const noexcept { return get() % n; }
template <typename U> inline constexpr auto operator &(U n) const noexcept { return get() & n; }
template <typename U> inline constexpr auto operator |(U n) const noexcept { return get() | n; }
template <typename U> inline constexpr auto operator ^(U n) const noexcept { return get() ^ n; }
inline constexpr T operator <<(int n) const noexcept { return get() << n; }
inline constexpr T operator >>(int n) const noexcept { return get() >> n; }
inline constexpr auto operator =(T n) { return set(n); }
constexpr byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
template <typename U> inline constexpr auto operator +=(U n) noexcept { return set(get() + n); }
template <typename U> inline constexpr auto operator -=(U n) noexcept { return set(get() - n); }
template <typename U> inline constexpr auto operator *=(U n) noexcept { return set(get() * n); }
template <typename U> inline constexpr auto operator /=(U n) noexcept { return set(get() / n); }
template <typename U> inline constexpr auto operator %=(U n) noexcept { return set(get() % n); }
inline constexpr auto operator &=(T n) noexcept { return set(get() & n); }
inline constexpr auto operator |=(T n) noexcept { return set(get() | n); }
inline constexpr auto operator ^=(T n) noexcept { return set(get() ^ n); }
inline constexpr auto operator <<=(int n) noexcept { return set(get() << n); }
inline constexpr auto operator >>=(int n) noexcept { return set(get() >> n); }
protected:
inline constexpr T get() const noexcept { return native_cast(_v); }
inline constexpr auto set(T n) noexcept { _v = bswap_cast(n); return *this; }
};
C++11 からの変更
返り値の型に auto を使用する
- template <typename U> inline constexpr decltype(T() + U()) operator +(U n) const noexcept { return get() + n; }
+ template <typename U> inline constexpr auto operator +(U n) const noexcept { return get() + n; }
return
文から型推定してくれるハズ。
const でないメンバ関数も constexpr とする
- template <typename U> inline byteswap_value<T>& operator +=(U n) noexcept { return set(get() + n); }
+ template <typename U> inline constexpr auto operator +=(U n) noexcept { return set(get() + n); }
アプリの constexpr 関数内のローカル変数に byteswap_value<T> 型が使用できるハズ。
その他
- 型選択を std::conditional から std::conditional_t に変更
テスト プログラム
endian-14.cpp (やや長いので折りたたみ)
#include "endian.hpp"
#include "byteswap.hpp"
// ----------------------------------------------------------------------------
#include <cstdint>
#include <limits>
/*
* byteswap_value
*/
template <typename T>
class byteswap_value
{
public:
using value_type = T; // byteswap する native の型.
protected:
/* 逆バイト順型 */
template <typename I> struct bswap { using type = I; };
template <> struct bswap<float> { using type = std::uint32_t; };
template <> struct bswap<double> { using type = std::uint64_t; };
using bswap_value = typename bswap<T>::type; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline constexpr bswap_cast(const T& n) noexcept : v(n) {}
inline constexpr operator bswap_value() const noexcept
{ return std::byteswap(*(const bswap_value*)&v); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline constexpr native_cast(const bswap_value& s) noexcept : v(std::byteswap(s)) {}
inline constexpr operator T() const noexcept { return *(const T*)&v; }
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
byteswap_value() noexcept = default;
inline constexpr byteswap_value(T d) noexcept : _v(bswap_cast(d)) {}
constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
inline constexpr operator T() const noexcept { return get(); }
inline constexpr bool operator !() const noexcept { return !_v; }
inline constexpr bool operator ==(const byteswap_value<T>& s) const noexcept { return _v == s._v; }
inline constexpr bool operator !=(const byteswap_value<T>& s) const noexcept { return _v != s._v; }
template <typename U> inline constexpr bool operator < (U n) const noexcept { return get() < n; }
template <typename U> inline constexpr bool operator <=(U n) const noexcept { return get() <= n; }
template <typename U> inline constexpr bool operator ==(U n) const noexcept { return get() == n; }
template <typename U> inline constexpr bool operator !=(U n) const noexcept { return get() != n; }
template <typename U> inline constexpr bool operator >=(U n) const noexcept { return get() >= n; }
template <typename U> inline constexpr bool operator > (U n) const noexcept { return get() > n; }
inline constexpr T operator +() const noexcept { return +get(); }
inline constexpr T operator -() const noexcept { return -get(); }
inline constexpr T operator ~() const noexcept { return ~get(); }
template <typename U> inline constexpr auto operator +(U n) const noexcept { return get() + n; }
template <typename U> inline constexpr auto operator -(U n) const noexcept { return get() - n; }
template <typename U> inline constexpr auto operator *(U n) const noexcept { return get() * n; }
template <typename U> inline constexpr auto operator /(U n) const noexcept { return get() / n; }
template <typename U> inline constexpr auto operator %(U n) const noexcept { return get() % n; }
template <typename U> inline constexpr auto operator &(U n) const noexcept { return get() & n; }
template <typename U> inline constexpr auto operator |(U n) const noexcept { return get() | n; }
template <typename U> inline constexpr auto operator ^(U n) const noexcept { return get() ^ n; }
inline constexpr T operator <<(int n) const noexcept { return get() << n; }
inline constexpr T operator >>(int n) const noexcept { return get() >> n; }
inline constexpr auto operator =(T n) { return set(n); }
constexpr byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
template <typename U> inline constexpr auto operator +=(U n) noexcept { return set(get() + n); }
template <typename U> inline constexpr auto operator -=(U n) noexcept { return set(get() - n); }
template <typename U> inline constexpr auto operator *=(U n) noexcept { return set(get() * n); }
template <typename U> inline constexpr auto operator /=(U n) noexcept { return set(get() / n); }
template <typename U> inline constexpr auto operator %=(U n) noexcept { return set(get() % n); }
inline constexpr auto operator &=(T n) noexcept { return set(get() & n); }
inline constexpr auto operator |=(T n) noexcept { return set(get() | n); }
inline constexpr auto operator ^=(T n) noexcept { return set(get() ^ n); }
inline constexpr auto operator <<=(int n) noexcept { return set(get() << n); }
inline constexpr auto operator >>=(int n) noexcept { return set(get() >> n); }
protected:
inline constexpr T get() const noexcept { return native_cast(_v); }
inline constexpr auto set(T n) noexcept { _v = bswap_cast(n); return *this; }
};
// ----------------------------------------------------------------------------
#include <string>
struct native_endian
{
enum {
is_big = std::endian::big == std::endian::native,
is_little = std::endian::little == std::endian::native,
};
using int8_type = std::int8_t;
using int16_type = std::int16_t;
using int32_type = std::int32_t;
using int64_type = std::int64_t;
using uint8_type = std::uint8_t;
using uint16_type = std::uint16_t;
using uint32_type = std::uint32_t;
using uint64_type = std::uint64_t;
using float32_type = float;
using float64_type = double;
using char_type = char;
using wchar_type = wchar_t;
using char16_type = char16_t;
using char32_type = char32_t;
};
struct byteswap_endian
{
enum {
is_big = !native_endian::is_big,
is_little = !native_endian::is_little,
};
using int8_type = native_endian::int8_type;
using int16_type = byteswap_value<native_endian::int16_type>;
using int32_type = byteswap_value<native_endian::int32_type>;
using int64_type = byteswap_value<native_endian::int64_type>;
using uint8_type = native_endian::uint8_type;
using uint16_type = byteswap_value<native_endian::uint16_type>;
using uint32_type = byteswap_value<native_endian::uint32_type>;
using uint64_type = byteswap_value<native_endian::uint64_type>;
using float32_type = byteswap_value<native_endian::float32_type>;
using float64_type = byteswap_value<native_endian::float64_type>;
using char_type = byteswap_value<native_endian::char_type>;
using wchar_type = byteswap_value<native_endian::wchar_type>;
using char16_type = byteswap_value<native_endian::char16_type>;
using char32_type = byteswap_value<native_endian::char32_type>;
};
template <bool big>
using fixed_endian = std::conditional_t<
big == native_endian::is_big, native_endian, byteswap_endian>;
/* big endian */
using big_endian = fixed_endian<true>;
using int8be_t = big_endian::int8_type;
using int16be_t = big_endian::int16_type;
using int32be_t = big_endian::int32_type;
using int64be_t = big_endian::int64_type;
using uint8be_t = big_endian::uint8_type;
using uint16be_t = big_endian::uint16_type;
using uint32be_t = big_endian::uint32_type;
using uint64be_t = big_endian::uint64_type;
using float32be_t = big_endian::float32_type;
using float64be_t = big_endian::float64_type;
using charbe_t = big_endian::char_type;
using wcharbe_t = big_endian::wchar_type;
using char16be_t = big_endian::char16_type;
using char32be_t = big_endian::char32_type;
using stringbe = std::basic_string<charbe_t>;
using wstringbe = std::basic_string<wcharbe_t>;
using u16stringbe = std::basic_string<char16be_t>;
using u32stringbe = std::basic_string<char32be_t>;
/* little endian */
using little_endian = fixed_endian<false>;
using int8le_t = little_endian::int8_type;
using int16le_t = little_endian::int16_type;
using int32le_t = little_endian::int32_type;
using int64le_t = little_endian::int64_type;
using uint8le_t = little_endian::uint8_type;
using uint16le_t = little_endian::uint16_type;
using uint32le_t = little_endian::uint32_type;
using uint64le_t = little_endian::uint64_type;
using float32le_t = little_endian::float32_type;
using float64le_t = little_endian::float64_type;
using charle_t = little_endian::char_type;
using wcharle_t = little_endian::wchar_type;
using char16le_t = little_endian::char16_type;
using char32le_t = little_endian::char32_type;
using stringle = std::basic_string<charle_t>;
using wstringle = std::basic_string<wcharle_t>;
using u16stringle = std::basic_string<char16le_t>;
using u32stringle = std::basic_string<char32le_t>;
// ----------------------------------------------------------------------------
/*
* テスト
*/
#include <algorithm>
#include <cstdio>
#include <typeinfo>
static const uint16_t native_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint16be_t big_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint16le_t little_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint32_t native_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint32be_t big_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint32le_t little_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint64_t native_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const uint64be_t big_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const uint64le_t little_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const float native_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32be_t big_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32le_t little_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static const double native_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64be_t big_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64le_t little_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static void dumpbin(const char* msg, const void* s, size_t n)
{
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
size_t x, y, ny = n & ~15, nr = n & 15;
printf("address = %p: %s\n", s, msg);
for (y = 0; y < ny; y += 16)
{
printf(" ");
for (size_t x = 0; x < 16; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
if (y < n)
{
printf(" ");
for (x = 0; x < nr; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
}
template <typename T>
inline static void dumpbin(const char* msg, const T& s)
{
dumpbin(msg, &s, sizeof(T));
}
template <typename T>
inline static void dumpbin(const char* msg, const std::basic_string<T>& s)
{
dumpbin(msg, s.data(), s.size() * sizeof(T));
}
template <typename T>
inline static const char *gettypename()
{
return typeid(T()).name();
}
template <typename T>
inline static const char *gettypename(const T v)
{
return typeid(v).name();
}
template <typename T>
inline static const char *valuetypename()
{
return typeid(T(0)).name();
}
template <typename T>
static void rtypename(const char* name, const T& x)
{
int8_t i8 = 11;
int16_t i16 = 12;
int32_t i32 = 14;
int64_t i64 = 18;
uint8_t u8 = 21;
uint16_t u16 = 22;
uint32_t u32 = 24;
uint64_t u64 = 28;
float f32 = 1.5;
double f64 = 2.25;
char c8 = 1;
wchar_t wc = 2;
char16_t c16 = 2;
char32_t c32 = 4;
printf("%s = %s\n", name, gettypename(x));
printf(" +i8:%s +i16:%s +i32:%s +i64:%s\n",
gettypename(x + i8), gettypename(x + i16),
gettypename(x + i32), gettypename(x + i64));
printf(" +u8:%s +u16:%s +u32:%s +u64:%s\n",
gettypename(x + u8), gettypename(x + u16),
gettypename(x + u32), gettypename(x + u64));
printf(" +c8:%s +c16:%s +c32:%s +wc:%s\n",
gettypename(x + c8), gettypename(x + c16),
gettypename(x + c32), gettypename(x + wc));
printf(" +f32:%s +f64:%s\n",
gettypename(x + f32), gettypename(x + f64));
printf("\n");
#if 0
T y = 0;
printf(" +=i8:%s +=i16:%s +=i32:%s +i64:%s\n",
gettypename(y += i8), gettypename(y += i16),
gettypename(y += i32), gettypename(y += i64));
printf(" +=u8:%s +=u16:%s +=u32:%s +=u64:%s\n",
gettypename(y += u8), gettypename(y += u16),
gettypename(y += u32), gettypename(y += u64));
printf(" +=f32:%s +=f64:%s\n",
gettypename(y += f32), gettypename(y += f64));
printf(" +=c8:%s +=wc:%s\n",
gettypename(y += c8), gettypename(y += wc));
printf("\n");
#endif
}
/*
*
*/
int main()
{
#ifdef __cplusplus
printf("compiler: __cplusplus = %ld\n", __cplusplus);
#endif
#ifdef _MSVC_LANG
printf("compiler: _MSVC_LANG = %ld\n", _MSVC_LANG);
#endif
printf("endian: native = %s\n", native_endian::is_big ? "big" : "little");
printf("\n");
dumpbin("native_data_u16", native_data_u16);
dumpbin("big_data_u16", big_data_u16);
dumpbin("little_data_u16", little_data_u16);
printf("\n");
dumpbin("native_data_u32", native_data_u32);
dumpbin("big_data_u32", big_data_u32);
dumpbin("little_data_u32", little_data_u32);
printf("\n");
dumpbin("native_data_u64", native_data_u64);
dumpbin("big_data_u64", big_data_u64);
dumpbin("little_data_u64", little_data_u64);
printf("\n");
dumpbin("native_data_f32", native_data_f32);
dumpbin("big_data_f32", big_data_f32);
dumpbin("little_data_f32", little_data_f32);
printf("\n");
dumpbin("native_data_f64", native_data_f64);
dumpbin("big_data_f64", big_data_f64);
dumpbin("little_data_f64", little_data_f64);
printf("\n");
int16be_t i16be = 32;
int32be_t i32be = 34;
int64be_t i64be = 38;
uint16be_t u16be = 42;
uint32be_t u32be = 44;
uint64be_t u64be = 48;
float32be_t f32be = 4.25;
float64be_t f64be = 8.125;
int16le_t i16le = i16be;
int32le_t i32le = i32be;
int64le_t i64le = i64be;
uint16le_t u16le = u16be;
uint32le_t u32le = u32be;
uint64le_t u64le = u64be;
float32le_t f32le = f32be;
float64le_t f64le = f64be;
/**/
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
dumpbin("float32be_t", f32be); dumpbin("float32le_t", f32le);
dumpbin("float64be_t", f64be); dumpbin("float64le_t", f64le);
printf("\n");
/**/
u16be = 32; u32be = 34; u64be = 38;
i16be = 42; i32be = 44; i64be = 48;
u16le = 32; u32le = 34; u64le = 38;
i16le = 42; i32le = 44; i64le = 48;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
u16be <<= 4; u32be <<= 4; u64be <<= 4;
i16be <<= 4; i32be <<= 4; i64be <<= 4;
u16le <<= 4; u32le <<= 4; u64le <<= 4;
i16le <<= 4; i32le <<= 4; i64le <<= 4;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
printf("compare:\n");
#define COMP(l,op,r) \
printf(" %s(%d) %-2s %s(%d) : %s\n", \
#l, (int)l, #op, #r, (int)r, \
(l op r) ? "true" : "false")
COMP(i16be, < , i16le); COMP(i16be, <=, i16le); COMP(i16be, ==, i16le);
COMP(i16be, !=, i16le); COMP(i16be, >=, i16le); COMP(i16be, > , i16le);
printf("\n");
COMP(i32be, < , i16le); COMP(i32be, <=, i16le); COMP(i32be, ==, i16le);
COMP(i32be, !=, i16le); COMP(i32be, >=, i16le); COMP(i32be, > , i16le);
printf("\n");
COMP(i32be, < , i64be); COMP(i32be, <=, i64be); COMP(i32be, ==, i64be);
COMP(i32be, !=, i64be); COMP(i32be, >=, i64be); COMP(i32be, > , i64be);
printf("\n");
COMP(i32be, < , i64le); COMP(i32be, <=, i64le); COMP(i32be, ==, i64le);
COMP(i32be, !=, i64le); COMP(i32be, >=, i64le); COMP(i32be, > , i64le);
printf("\n");
/**/
printf("typeid:\n");
printf(" int8_t:%s int16_t:%s int32_t:%s int64_t:%s\n",
valuetypename<int8_t>(), valuetypename<int16_t>(),
valuetypename<int32_t>(), valuetypename<int64_t>());
printf(" uint8_t:%s uint16_t:%s uint32_t:%s uint64_t:%s\n",
valuetypename<uint8_t>(), valuetypename<uint16_t>(),
valuetypename<uint32_t>(), valuetypename<uint64_t>());
printf(" float:%s double:%s\n", valuetypename<float>(), valuetypename<double>());
printf(" char:%s wchar_t:%s\n", valuetypename<char>(), valuetypename<wchar_t>());
printf(" int:%s unsigned:%s\n", valuetypename<int>(), valuetypename<unsigned>());
printf(" sizeof(wchar_t):%zd\n", sizeof(wchar_t));
printf("\n");
/**/
rtypename("int16be_t", i16be); rtypename("int16le_t", i16le);
rtypename("int32be_t", i32be); rtypename("int32le_t", i32le);
rtypename("int64be_t", i64be); rtypename("int64le_t", i64le);
rtypename("uint16be_t", u16be); rtypename("uint16le_t", u16le);
rtypename("uint32be_t", u32be); rtypename("uint32le_t", u32le);
rtypename("uint64be_t", u64be); rtypename("uint64le_t", u64le);
rtypename("float32be_t", f32be); rtypename("float32le_t", f32le);
rtypename("float64be_t", f64be); rtypename("float64le_t", f64le);
/**/
std::wstring ws(L"サンプルTEXT");
wstringbe wsbe(ws.begin(), ws.end());
wstringle wsle(ws.begin(), ws.end());
dumpbin("wstring", ws);
dumpbin("wstringbe", wsbe);
dumpbin("wstringle", wsle);
printf("\n");
std::u16string u16s(ws.begin(), ws.end()); /* sizeof(wchar_t) != sizeof(char16_t) の場合は要注意 */
u16stringbe u16sbe(u16s.begin(), u16s.end());
u16stringle u16sle(u16s.begin(), u16s.end());
dumpbin("u16string", u16s);
dumpbin("u16stringbe", u16sbe);
dumpbin("u16stringle", u16sle);
printf("\n");
std::u32string u32s(ws.begin(), ws.end()); /* sizeof(wchar_t) != sizeof(char32_t) の場合は要注意 */
u32stringbe u32sbe(u32s.begin(), u32s.end());
u32stringle u32sle(u32s.begin(), u32s.end());
dumpbin("u32string", u32s);
dumpbin("u32stringbe", u32sbe);
dumpbin("u32stringle", u32sle);
printf("\n");
return 0;
}
$ clang++ -O3 -g0 -DNDEBUG=1 -std=c++14 endian-14.cpp -o endian-14
$ ./endian-14
compiler: __cplusplus = 201402
endian: native = little
address = 0x10370b900: native_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x10370b910: big_data_u16
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10370b920: little_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x10370b930: native_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x10370b940: big_data_u32
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10370b950: little_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x10370b960: native_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x10370b970: big_data_u64
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x10370b980: little_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x10370b990: native_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x10370d000: big_data_f32
34 56 78 9a 45 67 89 ab 56 78 9a bc 76 54 32 10
address = 0x10370d030: little_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x10370b9a0: native_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x10370d010: big_data_f64
34 56 78 9a bc de f0 12 45 67 89 ab cd ef 01 23
56 78 9a bc de f0 12 34 76 54 32 10 fe dc ba 98
address = 0x10370d040: little_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x7ff7bc7f8630: i16be_t
00 20
address = 0x7ff7bc7f8636: i16le_t
20 00
address = 0x7ff7bc7f8620: u16be_t
00 2a
address = 0x7ff7bc7f861e: u16le_t
2a 00
address = 0x7ff7bc7f8628: i32be_t
00 00 00 22
address = 0x7ff7bc7f8600: i32le_t
22 00 00 00
address = 0x7ff7bc7f8618: u32be_t
00 00 00 2c
address = 0x7ff7bc7f8604: u32le_t
2c 00 00 00
address = 0x7ff7bc7f8610: i64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7bc7f8608: i64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7bc7f85f8: u64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7bc7f85f0: u64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7bc7f85e8: float32be_t
40 88 00 00
address = 0x7ff7bc7f85e4: float32le_t
00 00 88 40
address = 0x7ff7bc7f85d0: float64be_t
40 20 40 00 00 00 00 00
address = 0x7ff7bc7f85d8: float64le_t
00 00 00 00 00 40 20 40
address = 0x7ff7bc7f8630: i16be_t
00 2a
address = 0x7ff7bc7f8636: i16le_t
2a 00
address = 0x7ff7bc7f8620: u16be_t
00 20
address = 0x7ff7bc7f861e: u16le_t
20 00
address = 0x7ff7bc7f8628: i32be_t
00 00 00 2c
address = 0x7ff7bc7f8600: i32le_t
2c 00 00 00
address = 0x7ff7bc7f8618: u32be_t
00 00 00 22
address = 0x7ff7bc7f8604: u32le_t
22 00 00 00
address = 0x7ff7bc7f8610: i64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7bc7f8608: i64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7bc7f85f8: u64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7bc7f85f0: u64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7bc7f8630: i16be_t
02 a0
address = 0x7ff7bc7f8636: i16le_t
a0 02
address = 0x7ff7bc7f8620: u16be_t
02 00
address = 0x7ff7bc7f861e: u16le_t
00 02
address = 0x7ff7bc7f8628: i32be_t
00 00 02 c0
address = 0x7ff7bc7f8600: i32le_t
c0 02 00 00
address = 0x7ff7bc7f8618: u32be_t
00 00 02 20
address = 0x7ff7bc7f8604: u32le_t
20 02 00 00
address = 0x7ff7bc7f8610: i64be_t
00 00 00 00 00 00 03 00
address = 0x7ff7bc7f8608: i64le_t
00 03 00 00 00 00 00 00
address = 0x7ff7bc7f85f8: u64be_t
00 00 00 00 00 00 02 60
address = 0x7ff7bc7f85f0: u64le_t
60 02 00 00 00 00 00 00
compare:
i16be(672) < i16le(672) : false
i16be(672) <= i16le(672) : true
i16be(672) == i16le(672) : true
i16be(672) != i16le(672) : false
i16be(672) >= i16le(672) : true
i16be(672) > i16le(672) : false
i32be(704) < i16le(672) : false
i32be(704) <= i16le(672) : false
i32be(704) == i16le(672) : false
i32be(704) != i16le(672) : true
i32be(704) >= i16le(672) : true
i32be(704) > i16le(672) : true
i32be(704) < i64be(768) : true
i32be(704) <= i64be(768) : true
i32be(704) == i64be(768) : false
i32be(704) != i64be(768) : true
i32be(704) >= i64be(768) : false
i32be(704) > i64be(768) : false
i32be(704) < i64le(768) : true
i32be(704) <= i64le(768) : true
i32be(704) == i64le(768) : false
i32be(704) != i64le(768) : true
i32be(704) >= i64le(768) : false
i32be(704) > i64le(768) : false
typeid:
int8_t:a int16_t:s int32_t:i int64_t:x
uint8_t:h uint16_t:t uint32_t:j uint64_t:y
float:f double:d
char:c wchar_t:w
int:i unsigned:j
sizeof(wchar_t):4
int16be_t = 14byteswap_valueIsE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int16le_t = s
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int32be_t = 14byteswap_valueIiE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int32le_t = i
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int64be_t = 14byteswap_valueIxE
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+c8:x +c16:x +c32:x +wc:x
+f32:f +f64:d
int64le_t = x
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+c8:x +c16:x +c32:x +wc:x
+f32:f +f64:d
uint16be_t = 14byteswap_valueItE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
uint16le_t = t
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
uint32be_t = 14byteswap_valueIjE
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+c8:j +c16:j +c32:j +wc:j
+f32:f +f64:d
uint32le_t = j
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+c8:j +c16:j +c32:j +wc:j
+f32:f +f64:d
uint64be_t = 14byteswap_valueIyE
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+c8:y +c16:y +c32:y +wc:y
+f32:f +f64:d
uint64le_t = y
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+c8:y +c16:y +c32:y +wc:y
+f32:f +f64:d
float32be_t = 14byteswap_valueIfE
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+c8:f +c16:f +c32:f +wc:f
+f32:f +f64:d
float32le_t = f
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+c8:f +c16:f +c32:f +wc:f
+f32:f +f64:d
float64be_t = 14byteswap_valueIdE
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+c8:d +c16:d +c32:d +wc:d
+f32:d +f64:d
float64le_t = d
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+c8:d +c16:d +c32:d +wc:d
+f32:d +f64:d
address = 0x6000021b4000: wstring
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x6000021b4030: wstringbe
00 00 30 b5 00 00 30 f3 00 00 30 d7 00 00 30 eb
00 00 00 54 00 00 00 45 00 00 00 58 00 00 00 54
address = 0x6000021b4060: wstringle
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x7ff7bc7f859a: u16string
b5 30 f3 30 d7 30 eb 30 54 00 45 00 58 00 54 00
address = 0x7ff7bc7f8552: u16stringbe
30 b5 30 f3 30 d7 30 eb 00 54 00 45 00 58 00 54
address = 0x7ff7bc7f856a: u16stringle
b5 30 f3 30 d7 30 eb 30 54 00 45 00 58 00 54 00
address = 0x6000021b4090: u32string
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x6000021b40c0: u32stringbe
00 00 30 b5 00 00 30 f3 00 00 30 d7 00 00 30 eb
00 00 00 54 00 00 00 45 00 00 00 58 00 00 00 54
address = 0x6000021b40f0: u32stringle
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
C++17 では byteswap_value に変化なし
std::basic_string_view
を使う場合は
+using wstringbe_view = std::basic_string_view<wcharbe_t>;
+using u16stringbe_view = std::basic_string_view<char16be_t>;
+using u32stringbe_view = std::basic_string_view<char32be_t>;
+using wstringle_view = std::basic_string_view<wcharle_t>;
+using u16stringle_view = std::basic_string_view<char16le_t>;
+using u32stringle_view = std::basic_string_view<char32le_t>;
が可能。
C++20 で書いてみる
template <typename T>
class byteswap_value
{
public:
using value_type = T; // byteswap する native の型.
protected:
/* 逆バイト順型 */
template <typename I> struct bswap { using type = I; };
template <> struct bswap<float> { using type = std::uint32_t; };
template <> struct bswap<double> { using type = std::uint64_t; };
using bswap_value = bswap<T>::type; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline constexpr bswap_cast(const T& n) noexcept : v(n) {}
inline constexpr operator bswap_value() const noexcept
{ return std::byteswap(std::bit_cast<bswap_value>(v)); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline constexpr native_cast(const bswap_value& s) noexcept : v(std::byteswap(s)) {}
inline constexpr operator T() const noexcept { return std::bit_cast<T>(v); }
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
byteswap_value() noexcept = default;
inline constexpr byteswap_value(T d) noexcept : _v(bswap_cast(d)) {}
constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
inline constexpr operator T() const noexcept { return get(); }
inline constexpr bool operator !() const noexcept { return !_v; }
inline constexpr bool operator ==(const byteswap_value<T>& s) const noexcept { return _v == s._v; }
inline constexpr bool operator ==(auto n) const noexcept { return get() == n; }
inline constexpr auto operator <=>(auto n) const noexcept { return get() <=> n; }
inline constexpr T operator +() const noexcept { return +get(); }
inline constexpr T operator -() const noexcept { return -get(); }
inline constexpr T operator ~() const noexcept { return ~get(); }
inline constexpr auto operator +(auto n) const noexcept { return get() + n; }
inline constexpr auto operator -(auto n) const noexcept { return get() - n; }
inline constexpr auto operator *(auto n) const noexcept { return get() * n; }
inline constexpr auto operator /(auto n) const noexcept { return get() / n; }
inline constexpr auto operator %(auto n) const noexcept { return get() % n; }
inline constexpr auto operator &(auto n) const noexcept { return get() & n; }
inline constexpr auto operator |(auto n) const noexcept { return get() | n; }
inline constexpr auto operator ^(auto n) const noexcept { return get() ^ n; }
inline constexpr T operator <<(int n) const noexcept { return get() << n; }
inline constexpr T operator >>(int n) const noexcept { return get() >> n; }
inline constexpr auto operator =(T n) { return set(n); }
constexpr byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
inline constexpr auto operator +=(auto n) noexcept { return set(get() + n); }
inline constexpr auto operator -=(auto n) noexcept { return set(get() - n); }
inline constexpr auto operator *=(auto n) noexcept { return set(get() * n); }
inline constexpr auto operator /=(auto n) noexcept { return set(get() / n); }
inline constexpr auto operator %=(auto n) noexcept { return set(get() % n); }
inline constexpr auto operator &=(T n) noexcept { return set(get() & n); }
inline constexpr auto operator |=(T n) noexcept { return set(get() | n); }
inline constexpr auto operator ^=(T n) noexcept { return set(get() ^ n); }
inline constexpr auto operator <<=(int n) noexcept { return set(get() << n); }
inline constexpr auto operator >>=(int n) noexcept { return set(get() >> n); }
protected:
inline constexpr T get() const noexcept { return native_cast(_v); }
inline constexpr auto set(T n) noexcept { _v = bswap_cast(n); return *this; }
};
C++14 からの変更
typename の省略
typename キーワードが不要な場合がある。
- using bswap_value = typename bswap<T>::type; // byteswap 値の型.
+ using bswap_value = bswap<T>::type; // byteswap 値の型.
メンバ関数の引数に auto を使用する
テンプレート部分が不要になった。
- template <typename U> inline constexpr auto operator +(U n) const noexcept { return get() + n; }
+ inline constexpr auto operator +(auto n) const noexcept { return get() + n; }
関係演算子の省略
三方比較演算子 '<=>'
により '<', '<=', '>=', '>'
を、等値演算子 '=='
により、非等値演算子 '!='
を省略した。
+ inline constexpr bool operator ==(auto n) const noexcept { return get() == n; }
+ inline constexpr auto operator <=>(auto n) const noexcept { return get() <=> n; }
- inline constexpr bool operator !=(const byteswap_value<T>& s) const noexcept { return _v != s._v; }
- template <typename U> inline constexpr bool operator < (U n) const noexcept { return get() < n; }
- template <typename U> inline constexpr bool operator <=(U n) const noexcept { return get() <= n; }
- template <typename U> inline constexpr bool operator ==(U n) const noexcept { return get() == n; }
- template <typename U> inline constexpr bool operator !=(U n) const noexcept { return get() != n; }
- template <typename U> inline constexpr bool operator >=(U n) const noexcept { return get() >= n; }
- template <typename U> inline constexpr bool operator > (U n) const noexcept { return get() > n; }
std::bit_cast を使用する
@yaito3014 さんの指摘により追加
- { return std::byteswap(*(const bswap_value*)&v); }
+ { return std::byteswap(std::bit_cast<bswap_value>(v)); }
- inline constexpr operator T() const noexcept { return *(const T*)&v; }
+ inline constexpr operator T() const noexcept { return std::bit_cast<T>(v); }
その他
-
char8_t
に対する定義を追加(各エンディアン型)
テスト プログラム
endian-20.cpp (やや長いので折りたたみ)
#include "endian.hpp"
#include "byteswap.hpp"
// ----------------------------------------------------------------------------
#include <cstdint>
#include <compare>
#include <limits>
/*
* byteswap_value
*/
template <typename T>
class byteswap_value
{
public:
using value_type = T; // byteswap する native の型.
protected:
/* 逆バイト順型 */
template <typename I> struct bswap { using type = I; };
template <> struct bswap<float> { using type = std::uint32_t; };
template <> struct bswap<double> { using type = std::uint64_t; };
using bswap_value = bswap<T>::type; // byteswap 値の型.
/* bswap_value への型変換 */
struct bswap_cast
{
T v;
inline constexpr bswap_cast(const T& n) noexcept : v(n) {}
inline constexpr operator bswap_value() const noexcept
{ return std::byteswap(std::bit_cast<bswap_value>(v)); }
};
/* bswap_value からの型変換 */
struct native_cast
{
bswap_value v;
inline constexpr native_cast(const bswap_value& s) noexcept : v(std::byteswap(s)) {}
inline constexpr operator T() const noexcept { return std::bit_cast<T>(v); }
};
protected:
bswap_value _v; // byteswap された値を保持する.
public:
byteswap_value() noexcept = default;
inline constexpr byteswap_value(T d) noexcept : _v(bswap_cast(d)) {}
constexpr byteswap_value(const byteswap_value<T>& s) noexcept = default;
inline constexpr operator T() const noexcept { return get(); }
inline constexpr bool operator !() const noexcept { return !_v; }
inline constexpr bool operator ==(const byteswap_value<T>& s) const noexcept { return _v == s._v; }
inline constexpr bool operator ==(auto n) const noexcept { return get() == n; }
inline constexpr auto operator <=>(auto n) const noexcept { return get() <=> n; }
inline constexpr T operator +() const noexcept { return +get(); }
inline constexpr T operator -() const noexcept { return -get(); }
inline constexpr T operator ~() const noexcept { return ~get(); }
inline constexpr auto operator +(auto n) const noexcept { return get() + n; }
inline constexpr auto operator -(auto n) const noexcept { return get() - n; }
inline constexpr auto operator *(auto n) const noexcept { return get() * n; }
inline constexpr auto operator /(auto n) const noexcept { return get() / n; }
inline constexpr auto operator %(auto n) const noexcept { return get() % n; }
inline constexpr auto operator &(auto n) const noexcept { return get() & n; }
inline constexpr auto operator |(auto n) const noexcept { return get() | n; }
inline constexpr auto operator ^(auto n) const noexcept { return get() ^ n; }
inline constexpr T operator <<(int n) const noexcept { return get() << n; }
inline constexpr T operator >>(int n) const noexcept { return get() >> n; }
inline constexpr auto operator =(T n) { return set(n); }
constexpr byteswap_value<T>& operator =(const byteswap_value<T>& s) noexcept = default;
inline constexpr auto operator +=(auto n) noexcept { return set(get() + n); }
inline constexpr auto operator -=(auto n) noexcept { return set(get() - n); }
inline constexpr auto operator *=(auto n) noexcept { return set(get() * n); }
inline constexpr auto operator /=(auto n) noexcept { return set(get() / n); }
inline constexpr auto operator %=(auto n) noexcept { return set(get() % n); }
inline constexpr auto operator &=(T n) noexcept { return set(get() & n); }
inline constexpr auto operator |=(T n) noexcept { return set(get() | n); }
inline constexpr auto operator ^=(T n) noexcept { return set(get() ^ n); }
inline constexpr auto operator <<=(int n) noexcept { return set(get() << n); }
inline constexpr auto operator >>=(int n) noexcept { return set(get() >> n); }
protected:
inline constexpr T get() const noexcept { return native_cast(_v); }
inline constexpr auto set(T n) noexcept { _v = bswap_cast(n); return *this; }
};
// ----------------------------------------------------------------------------
#include <string>
#include <string_view>
struct native_endian
{
enum {
is_big = std::endian::big == std::endian::native,
is_little = std::endian::little == std::endian::native,
};
using int8_type = std::int8_t;
using int16_type = std::int16_t;
using int32_type = std::int32_t;
using int64_type = std::int64_t;
using uint8_type = std::uint8_t;
using uint16_type = std::uint16_t;
using uint32_type = std::uint32_t;
using uint64_type = std::uint64_t;
using float32_type = float;
using float64_type = double;
using char_type = char;
using wchar_type = wchar_t;
using char8_type = char8_t;
using char16_type = char16_t;
using char32_type = char32_t;
};
struct byteswap_endian
{
enum {
is_big = !native_endian::is_big,
is_little = !native_endian::is_little,
};
using int8_type = native_endian::int8_type;
using int16_type = byteswap_value<native_endian::int16_type>;
using int32_type = byteswap_value<native_endian::int32_type>;
using int64_type = byteswap_value<native_endian::int64_type>;
using uint8_type = native_endian::uint8_type;
using uint16_type = byteswap_value<native_endian::uint16_type>;
using uint32_type = byteswap_value<native_endian::uint32_type>;
using uint64_type = byteswap_value<native_endian::uint64_type>;
using float32_type = byteswap_value<native_endian::float32_type>;
using float64_type = byteswap_value<native_endian::float64_type>;
using char_type = byteswap_value<native_endian::char_type>;
using wchar_type = byteswap_value<native_endian::wchar_type>;
using char8_type = byteswap_value<native_endian::char8_type>;
using char16_type = byteswap_value<native_endian::char16_type>;
using char32_type = byteswap_value<native_endian::char32_type>;
};
template <bool big>
using fixed_endian = std::conditional_t<
big == native_endian::is_big, native_endian, byteswap_endian>;
/* big endian */
using big_endian = fixed_endian<true>;
using int8be_t = big_endian::int8_type;
using int16be_t = big_endian::int16_type;
using int32be_t = big_endian::int32_type;
using int64be_t = big_endian::int64_type;
using uint8be_t = big_endian::uint8_type;
using uint16be_t = big_endian::uint16_type;
using uint32be_t = big_endian::uint32_type;
using uint64be_t = big_endian::uint64_type;
using float32be_t = big_endian::float32_type;
using float64be_t = big_endian::float64_type;
using charbe_t = big_endian::char_type;
using wcharbe_t = big_endian::wchar_type;
using char8be_t = big_endian::char8_type;
using char16be_t = big_endian::char16_type;
using char32be_t = big_endian::char32_type;
using wstringbe = std::basic_string<wcharbe_t>;
using u8stringbe = std::basic_string<char8be_t>;
using u16stringbe = std::basic_string<char16be_t>;
using u32stringbe = std::basic_string<char32be_t>;
using stringbe_view = std::basic_string_view<charbe_t>;
using wstringbe_view = std::basic_string_view<wcharbe_t>;
using u8stringbe_view = std::basic_string_view<char8be_t>;
using u16stringbe_view = std::basic_string_view<char16be_t>;
using u32stringbe_view = std::basic_string_view<char32be_t>;
/* little endian */
using little_endian = fixed_endian<false>;
using int8le_t = little_endian::int8_type;
using int16le_t = little_endian::int16_type;
using int32le_t = little_endian::int32_type;
using int64le_t = little_endian::int64_type;
using uint8le_t = little_endian::uint8_type;
using uint16le_t = little_endian::uint16_type;
using uint32le_t = little_endian::uint32_type;
using uint64le_t = little_endian::uint64_type;
using float32le_t = little_endian::float32_type;
using float64le_t = little_endian::float64_type;
using charle_t = little_endian::char_type;
using wcharle_t = little_endian::wchar_type;
using char8le_t = little_endian::char8_type;
using char16le_t = little_endian::char16_type;
using char32le_t = little_endian::char32_type;
using stringle = std::basic_string<charle_t>;
using wstringle = std::basic_string<wcharle_t>;
using u8stringle = std::basic_string<char8le_t>;
using u16stringle = std::basic_string<char16le_t>;
using u32stringle = std::basic_string<char32le_t>;
using stringle_view = std::basic_string_view<charle_t>;
using wstringle_view = std::basic_string_view<wcharle_t>;
using u8stringle_view = std::basic_string_view<char8le_t>;
using u16stringle_view = std::basic_string_view<char16le_t>;
using u32stringle_view = std::basic_string_view<char32le_t>;
// ----------------------------------------------------------------------------
/*
* テスト
*/
#include <algorithm>
#include <cstdio>
#include <typeinfo>
static const uint16_t native_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint16be_t big_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint16le_t little_data_u16[] = {
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
};
static const uint32_t native_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint32be_t big_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint32le_t little_data_u32[] = {
0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
};
static const uint64_t native_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const uint64be_t big_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const uint64le_t little_data_u64[] = {
0x0123456789abcdefULL, 0xfedcba9876543210ULL,
};
static const float native_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32be_t big_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static float32le_t little_data_f32[] = {
1.997417768961895490e-07, // 0x3456789a
3.704604248046875000e+03, // 0x456789ab
6.833586569216000000e+13, // 0x56789abc
1.075959298965006122e+33, // 0x76543210
};
static const double native_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64be_t big_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static float64le_t little_data_f64[] = {
1.4319418138097981587699937142696840e-56, // 0x3456789abcdef012
2.2764341833285411032321228800000000e+26, // 0x456789abcdef0123
3.6115365933711609499120338465022186e+108, // 0x56789abcdef01234
9.9364762676789442589659242262712990e+261, // 0x76543210fedcba98
};
static void dumpbin(const char* msg, const void* s, size_t n)
{
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
size_t x, y, ny = n & ~15, nr = n & 15;
printf("address = %p: %s\n", s, msg);
for (y = 0; y < ny; y += 16)
{
printf(" ");
for (size_t x = 0; x < 16; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
if (y < n)
{
printf(" ");
for (x = 0; x < nr; x++)
printf(" %02x", p[y + x]);
printf("\n");
}
}
template <typename T>
inline static void dumpbin(const char* msg, const T& s)
{
dumpbin(msg, &s, sizeof(T));
}
template <typename T>
inline static void dumpbin(const char* msg, const std::basic_string<T>& s)
{
dumpbin(msg, s.data(), s.size() * sizeof(T));
}
template <typename T>
inline static const char *gettypename()
{
return typeid(T()).name();
}
template <typename T>
inline static const char *gettypename(const T v)
{
return typeid(v).name();
}
template <typename T>
inline static const char *valuetypename()
{
return typeid(T(0)).name();
}
template <typename T>
static void rtypename(const char* name, const T& x)
{
int8_t i8 = 11;
int16_t i16 = 12;
int32_t i32 = 14;
int64_t i64 = 18;
uint8_t u8 = 21;
uint16_t u16 = 22;
uint32_t u32 = 24;
uint64_t u64 = 28;
float f32 = 1.5;
double f64 = 2.25;
char c8 = 1;
wchar_t wc = 2;
char16_t c16 = 2;
char32_t c32 = 4;
printf("%s = %s\n", name, gettypename(x));
printf(" +i8:%s +i16:%s +i32:%s +i64:%s\n",
gettypename(x + i8), gettypename(x + i16),
gettypename(x + i32), gettypename(x + i64));
printf(" +u8:%s +u16:%s +u32:%s +u64:%s\n",
gettypename(x + u8), gettypename(x + u16),
gettypename(x + u32), gettypename(x + u64));
printf(" +c8:%s +c16:%s +c32:%s +wc:%s\n",
gettypename(x + c8), gettypename(x + c16),
gettypename(x + c32), gettypename(x + wc));
printf(" +f32:%s +f64:%s\n",
gettypename(x + f32), gettypename(x + f64));
printf("\n");
#if 0
T y = 0;
printf(" +=i8:%s +=i16:%s +=i32:%s +i64:%s\n",
gettypename(y += i8), gettypename(y += i16),
gettypename(y += i32), gettypename(y += i64));
printf(" +=u8:%s +=u16:%s +=u32:%s +=u64:%s\n",
gettypename(y += u8), gettypename(y += u16),
gettypename(y += u32), gettypename(y += u64));
printf(" +=f32:%s +=f64:%s\n",
gettypename(y += f32), gettypename(y += f64));
printf(" +=c8:%s +=wc:%s\n",
gettypename(y += c8), gettypename(y += wc));
printf("\n");
#endif
}
/*
*
*/
int main()
{
#ifdef __cplusplus
printf("compiler: __cplusplus = %ld\n", __cplusplus);
#endif
#ifdef _MSVC_LANG
printf("compiler: _MSVC_LANG = %ld\n", _MSVC_LANG);
#endif
printf("endian: native = %s\n", native_endian::is_big ? "big" : "little");
printf("\n");
dumpbin("native_data_u16", native_data_u16);
dumpbin("big_data_u16", big_data_u16);
dumpbin("little_data_u16", little_data_u16);
printf("\n");
dumpbin("native_data_u32", native_data_u32);
dumpbin("big_data_u32", big_data_u32);
dumpbin("little_data_u32", little_data_u32);
printf("\n");
dumpbin("native_data_u64", native_data_u64);
dumpbin("big_data_u64", big_data_u64);
dumpbin("little_data_u64", little_data_u64);
printf("\n");
dumpbin("native_data_f32", native_data_f32);
dumpbin("big_data_f32", big_data_f32);
dumpbin("little_data_f32", little_data_f32);
printf("\n");
dumpbin("native_data_f64", native_data_f64);
dumpbin("big_data_f64", big_data_f64);
dumpbin("little_data_f64", little_data_f64);
printf("\n");
int16be_t i16be = 32;
int32be_t i32be = 34;
int64be_t i64be = 38;
uint16be_t u16be = 42;
uint32be_t u32be = 44;
uint64be_t u64be = 48;
float32be_t f32be = 4.25;
float64be_t f64be = 8.125;
int16le_t i16le = i16be;
int32le_t i32le = i32be;
int64le_t i64le = i64be;
uint16le_t u16le = u16be;
uint32le_t u32le = u32be;
uint64le_t u64le = u64be;
float32le_t f32le = f32be;
float64le_t f64le = f64be;
/**/
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
dumpbin("float32be_t", f32be); dumpbin("float32le_t", f32le);
dumpbin("float64be_t", f64be); dumpbin("float64le_t", f64le);
printf("\n");
/**/
u16be = 32; u32be = 34; u64be = 38;
i16be = 42; i32be = 44; i64be = 48;
u16le = 32; u32le = 34; u64le = 38;
i16le = 42; i32le = 44; i64le = 48;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
u16be <<= 4; u32be <<= 4; u64be <<= 4;
i16be <<= 4; i32be <<= 4; i64be <<= 4;
u16le <<= 4; u32le <<= 4; u64le <<= 4;
i16le <<= 4; i32le <<= 4; i64le <<= 4;
dumpbin("i16be_t", i16be); dumpbin("i16le_t", i16le);
dumpbin("u16be_t", u16be); dumpbin("u16le_t", u16le);
dumpbin("i32be_t", i32be); dumpbin("i32le_t", i32le);
dumpbin("u32be_t", u32be); dumpbin("u32le_t", u32le);
dumpbin("i64be_t", i64be); dumpbin("i64le_t", i64le);
dumpbin("u64be_t", u64be); dumpbin("u64le_t", u64le);
printf("\n");
/**/
printf("compare:\n");
#define COMP(l,op,r) \
printf(" %s(%d) %-2s %s(%d) : %s\n", \
#l, (int)l, #op, #r, (int)r, \
(l op r) ? "true" : "false")
COMP(i16be, < , i16le); COMP(i16be, <=, i16le); COMP(i16be, ==, i16le);
COMP(i16be, !=, i16le); COMP(i16be, >=, i16le); COMP(i16be, > , i16le);
printf("\n");
COMP(i32be, < , i16le); COMP(i32be, <=, i16le); COMP(i32be, ==, i16le);
COMP(i32be, !=, i16le); COMP(i32be, >=, i16le); COMP(i32be, > , i16le);
printf("\n");
COMP(i32be, < , i64be); COMP(i32be, <=, i64be); COMP(i32be, ==, i64be);
COMP(i32be, !=, i64be); COMP(i32be, >=, i64be); COMP(i32be, > , i64be);
printf("\n");
COMP(i32be, < , i64le); COMP(i32be, <=, i64le); COMP(i32be, ==, i64le);
COMP(i32be, !=, i64le); COMP(i32be, >=, i64le); COMP(i32be, > , i64le);
printf("\n");
/**/
printf("typeid:\n");
printf(" int8_t:%s int16_t:%s int32_t:%s int64_t:%s\n",
valuetypename<int8_t>(), valuetypename<int16_t>(),
valuetypename<int32_t>(), valuetypename<int64_t>());
printf(" uint8_t:%s uint16_t:%s uint32_t:%s uint64_t:%s\n",
valuetypename<uint8_t>(), valuetypename<uint16_t>(),
valuetypename<uint32_t>(), valuetypename<uint64_t>());
printf(" float:%s double:%s\n", valuetypename<float>(), valuetypename<double>());
printf(" char:%s wchar_t:%s\n", valuetypename<char>(), valuetypename<wchar_t>());
printf(" int:%s unsigned:%s\n", valuetypename<int>(), valuetypename<unsigned>());
printf(" sizeof(wchar_t):%zd\n", sizeof(wchar_t));
printf("\n");
/**/
rtypename("int16be_t", i16be); rtypename("int16le_t", i16le);
rtypename("int32be_t", i32be); rtypename("int32le_t", i32le);
rtypename("int64be_t", i64be); rtypename("int64le_t", i64le);
rtypename("uint16be_t", u16be); rtypename("uint16le_t", u16le);
rtypename("uint32be_t", u32be); rtypename("uint32le_t", u32le);
rtypename("uint64be_t", u64be); rtypename("uint64le_t", u64le);
rtypename("float32be_t", f32be); rtypename("float32le_t", f32le);
rtypename("float64be_t", f64be); rtypename("float64le_t", f64le);
/**/
std::wstring ws(L"サンプルTEXT");
wstringbe wsbe(ws.begin(), ws.end());
wstringle wsle(ws.begin(), ws.end());
dumpbin("wstring", ws);
dumpbin("wstringbe", wsbe);
dumpbin("wstringle", wsle);
printf("\n");
std::u16string u16s(ws.begin(), ws.end()); /* sizeof(wchar_t) != sizeof(char16_t) の場合は要注意 */
u16stringbe u16sbe(u16s.begin(), u16s.end());
u16stringle u16sle(u16s.begin(), u16s.end());
dumpbin("u16string", u16s);
dumpbin("u16stringbe", u16sbe);
dumpbin("u16stringle", u16sle);
printf("\n");
std::u32string u32s(ws.begin(), ws.end()); /* sizeof(wchar_t) != sizeof(char32_t) の場合は要注意 */
u32stringbe u32sbe(u32s.begin(), u32s.end());
u32stringle u32sle(u32s.begin(), u32s.end());
dumpbin("u32string", u32s);
dumpbin("u32stringbe", u32sbe);
dumpbin("u32stringle", u32sle);
printf("\n");
return 0;
}
$ clang++ -O3 -g0 -DNDEBUG=1 -std=c++20 endian-20.cpp -o endian-20
$ ./endian-20
compiler: __cplusplus = 202002
endian: native = little
address = 0x1001d4900: native_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x1001d4910: big_data_u16
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x1001d4920: little_data_u16
23 01 67 45 ab 89 ef cd dc fe 98 ba 54 76 10 32
address = 0x1001d4930: native_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x1001d4940: big_data_u32
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x1001d4950: little_data_u32
67 45 23 01 ef cd ab 89 98 ba dc fe 10 32 54 76
address = 0x1001d4960: native_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x1001d4970: big_data_u64
01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
address = 0x1001d4980: little_data_u64
ef cd ab 89 67 45 23 01 10 32 54 76 98 ba dc fe
address = 0x1001d4990: native_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x1001d6000: big_data_f32
34 56 78 9a 45 67 89 ab 56 78 9a bc 76 54 32 10
address = 0x1001d6030: little_data_f32
9a 78 56 34 ab 89 67 45 bc 9a 78 56 10 32 54 76
address = 0x1001d49a0: native_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x1001d6010: big_data_f64
34 56 78 9a bc de f0 12 45 67 89 ab cd ef 01 23
56 78 9a bc de f0 12 34 76 54 32 10 fe dc ba 98
address = 0x1001d6040: little_data_f64
12 f0 de bc 9a 78 56 34 23 01 ef cd ab 89 67 45
34 12 f0 de bc 9a 78 56 98 ba dc fe 10 32 54 76
address = 0x7ff7bfd2f630: i16be_t
00 20
address = 0x7ff7bfd2f636: i16le_t
20 00
address = 0x7ff7bfd2f620: u16be_t
00 2a
address = 0x7ff7bfd2f61e: u16le_t
2a 00
address = 0x7ff7bfd2f628: i32be_t
00 00 00 22
address = 0x7ff7bfd2f600: i32le_t
22 00 00 00
address = 0x7ff7bfd2f618: u32be_t
00 00 00 2c
address = 0x7ff7bfd2f604: u32le_t
2c 00 00 00
address = 0x7ff7bfd2f610: i64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7bfd2f608: i64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7bfd2f5f8: u64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7bfd2f5f0: u64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7bfd2f5e8: float32be_t
40 88 00 00
address = 0x7ff7bfd2f5e4: float32le_t
00 00 88 40
address = 0x7ff7bfd2f5d0: float64be_t
40 20 40 00 00 00 00 00
address = 0x7ff7bfd2f5d8: float64le_t
00 00 00 00 00 40 20 40
address = 0x7ff7bfd2f630: i16be_t
00 2a
address = 0x7ff7bfd2f636: i16le_t
2a 00
address = 0x7ff7bfd2f620: u16be_t
00 20
address = 0x7ff7bfd2f61e: u16le_t
20 00
address = 0x7ff7bfd2f628: i32be_t
00 00 00 2c
address = 0x7ff7bfd2f600: i32le_t
2c 00 00 00
address = 0x7ff7bfd2f618: u32be_t
00 00 00 22
address = 0x7ff7bfd2f604: u32le_t
22 00 00 00
address = 0x7ff7bfd2f610: i64be_t
00 00 00 00 00 00 00 30
address = 0x7ff7bfd2f608: i64le_t
30 00 00 00 00 00 00 00
address = 0x7ff7bfd2f5f8: u64be_t
00 00 00 00 00 00 00 26
address = 0x7ff7bfd2f5f0: u64le_t
26 00 00 00 00 00 00 00
address = 0x7ff7bfd2f630: i16be_t
02 a0
address = 0x7ff7bfd2f636: i16le_t
a0 02
address = 0x7ff7bfd2f620: u16be_t
02 00
address = 0x7ff7bfd2f61e: u16le_t
00 02
address = 0x7ff7bfd2f628: i32be_t
00 00 02 c0
address = 0x7ff7bfd2f600: i32le_t
c0 02 00 00
address = 0x7ff7bfd2f618: u32be_t
00 00 02 20
address = 0x7ff7bfd2f604: u32le_t
20 02 00 00
address = 0x7ff7bfd2f610: i64be_t
00 00 00 00 00 00 03 00
address = 0x7ff7bfd2f608: i64le_t
00 03 00 00 00 00 00 00
address = 0x7ff7bfd2f5f8: u64be_t
00 00 00 00 00 00 02 60
address = 0x7ff7bfd2f5f0: u64le_t
60 02 00 00 00 00 00 00
compare:
i16be(672) < i16le(672) : false
i16be(672) <= i16le(672) : true
i16be(672) == i16le(672) : true
i16be(672) != i16le(672) : false
i16be(672) >= i16le(672) : true
i16be(672) > i16le(672) : false
i32be(704) < i16le(672) : false
i32be(704) <= i16le(672) : false
i32be(704) == i16le(672) : false
i32be(704) != i16le(672) : true
i32be(704) >= i16le(672) : true
i32be(704) > i16le(672) : true
i32be(704) < i64be(768) : true
i32be(704) <= i64be(768) : true
i32be(704) == i64be(768) : false
i32be(704) != i64be(768) : true
i32be(704) >= i64be(768) : false
i32be(704) > i64be(768) : false
i32be(704) < i64le(768) : true
i32be(704) <= i64le(768) : true
i32be(704) == i64le(768) : false
i32be(704) != i64le(768) : true
i32be(704) >= i64le(768) : false
i32be(704) > i64le(768) : false
typeid:
int8_t:a int16_t:s int32_t:i int64_t:x
uint8_t:h uint16_t:t uint32_t:j uint64_t:y
float:f double:d
char:c wchar_t:w
int:i unsigned:j
sizeof(wchar_t):4
int16be_t = 14byteswap_valueIsE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int16le_t = s
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int32be_t = 14byteswap_valueIiE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int32le_t = i
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
int64be_t = 14byteswap_valueIxE
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+c8:x +c16:x +c32:x +wc:x
+f32:f +f64:d
int64le_t = x
+i8:x +i16:x +i32:x +i64:x
+u8:x +u16:x +u32:x +u64:y
+c8:x +c16:x +c32:x +wc:x
+f32:f +f64:d
uint16be_t = 14byteswap_valueItE
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
uint16le_t = t
+i8:i +i16:i +i32:i +i64:x
+u8:i +u16:i +u32:j +u64:y
+c8:i +c16:i +c32:j +wc:i
+f32:f +f64:d
uint32be_t = 14byteswap_valueIjE
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+c8:j +c16:j +c32:j +wc:j
+f32:f +f64:d
uint32le_t = j
+i8:j +i16:j +i32:j +i64:x
+u8:j +u16:j +u32:j +u64:y
+c8:j +c16:j +c32:j +wc:j
+f32:f +f64:d
uint64be_t = 14byteswap_valueIyE
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+c8:y +c16:y +c32:y +wc:y
+f32:f +f64:d
uint64le_t = y
+i8:y +i16:y +i32:y +i64:y
+u8:y +u16:y +u32:y +u64:y
+c8:y +c16:y +c32:y +wc:y
+f32:f +f64:d
float32be_t = 14byteswap_valueIfE
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+c8:f +c16:f +c32:f +wc:f
+f32:f +f64:d
float32le_t = f
+i8:f +i16:f +i32:f +i64:f
+u8:f +u16:f +u32:f +u64:f
+c8:f +c16:f +c32:f +wc:f
+f32:f +f64:d
float64be_t = 14byteswap_valueIdE
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+c8:d +c16:d +c32:d +wc:d
+f32:d +f64:d
float64le_t = d
+i8:d +i16:d +i32:d +i64:d
+u8:d +u16:d +u32:d +u64:d
+c8:d +c16:d +c32:d +wc:d
+f32:d +f64:d
address = 0x60000074c000: wstring
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x60000074c030: wstringbe
00 00 30 b5 00 00 30 f3 00 00 30 d7 00 00 30 eb
00 00 00 54 00 00 00 45 00 00 00 58 00 00 00 54
address = 0x60000074c060: wstringle
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x7ff7bfd2f59a: u16string
b5 30 f3 30 d7 30 eb 30 54 00 45 00 58 00 54 00
address = 0x7ff7bfd2f552: u16stringbe
30 b5 30 f3 30 d7 30 eb 00 54 00 45 00 58 00 54
address = 0x7ff7bfd2f56a: u16stringle
b5 30 f3 30 d7 30 eb 30 54 00 45 00 58 00 54 00
address = 0x600000740000: u32string
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
address = 0x600000740030: u32stringbe
00 00 30 b5 00 00 30 f3 00 00 30 d7 00 00 30 eb
00 00 00 54 00 00 00 45 00 00 00 58 00 00 00 54
address = 0x600000740060: u32stringle
b5 30 00 00 f3 30 00 00 d7 30 00 00 eb 30 00 00
54 00 00 00 45 00 00 00 58 00 00 00 54 00 00 00
言語仕様の進化の恩恵を受けられるのはいいのだけど...