boost/spirit/home/support/detail/integer/endian.hpp を参考に書いてみた
以下のような感じで定義しておいて
template <class T, std::size_t S> struct little_endian { static inline void set(char* const buf, const T &t) { *buf = t & 0xff; little_endian<T, S - 1>::set(buf + 1, t >> 8); } static inline T get(const char* const buf) { return *buf | little_endian<T, S - 1>::get(buf + 1) << 8; } }; template <class T> struct little_endian<T, 0> { static inline void set(char* const buf, const T &t) { } static inline T get(const char* const buf) { return 0; } };
以下のように使う
char buf[sizeof(int)]; // バイト列化 little_endian<int, sizeof(int)>::set(buf, 1000); // 復元 int i = little_endian<int, sizeof(int)>::get(buf);
アセンブラを見てみる
たとえば、以下のようにインスタンス化してみると
#include <cstddef> template <class T, std::size_t S> struct little_endian { static inline void set(char* const buf, const T &t) { *buf = t & 0xff; little_endian<T, S - 1>::set(buf + 1, t >> 8); } static inline T get(const char* const buf) { return *buf | little_endian<T, S - 1>::get(buf + 1) << 8; } }; template <class T> struct little_endian<T, 0> { static inline void set(char* const buf, const T &t) { } static inline T get(const char* const buf) { return 0; } }; // 明示的にインスタンス化する template void little_endian<int, sizeof(int)>::set(char* const buf, const int &t); template int little_endian<int, sizeof(int)>::get(const char* const buf);
以下のようなアセンブラになる
_ZN13little_endianIiLm4EE3setEPcRKi: movl (%rsi), %eax movb %al, (%rdi) movl (%rsi), %eax sarl $8, %eax movb %al, 1(%rdi) sarl $8, %eax movb %al, 2(%rdi) sarl $8, %eax movb %al, 3(%rdi) ret _ZN13little_endianIiLm4EE3getEPKc: movsbl 2(%rdi),%edx movsbl 3(%rdi),%eax sall $8, %eax orl %edx, %eax movsbl 1(%rdi),%edx sall $8, %eax orl %edx, %eax movsbl (%rdi),%edx sall $8, %eax orl %edx, %eax ret
テンプレートを使わない場合のアセンブラを見てみる
試しに、以下のように for 文を使うと
void little_endian_set(char* const buf, int a) { for (std::size_t i = 0; i < sizeof(int); ++i) { buf[i] =a & 0xff; a >>= 8; } } int little_endian_get(const char* const buf) { int r = 0; for (std::size_t i = 0; i < sizeof(int); ++i) { r = buf[i] | r << 8; } return r; }
以下のようなアセンブラになった
_Z17little_endian_setPci: movb %sil, (%rdi) movl %esi, %eax sarl $8, %eax movb %al, 1(%rdi) movl %esi, %eax sarl $16, %eax movb %al, 2(%rdi) sarl $24, %esi movb %sil, 3(%rdi) ret _Z17little_endian_getPKc: movsbl (%rdi),%eax sall $8, %eax movsbl 1(%rdi),%edx orl %edx, %eax sall $8, %eax movsbl 2(%rdi),%edx orl %edx, %eax sall $8, %eax movsbl 3(%rdi),%edx orl %edx, %eax ret
あれ、あんまり大差ない?