【C言語】
unionを使って
エンディアン変換を実装する

■unionと構造体との違いとは

簡単に言うと構造体のメンバを重ねて参照するのがunionです。

例えば
32bit(4byte)のメモリ領域を
1つの32bit変数として見たり
4つの8bit変数として見たりする時便利です。


16bitスワップ

uint16_t  bswap_16(uint16_t x){
  union   {
    uint16_t  bit16;
    struct    {uint8_t  b1,b2;} bit8x2;  
  } y,z ;
  y.bit16 = x ;
  z.bit8x2.b1 = y.bit8x2.b2;
  z.bit8x2.b2 = y.bit8x2.b1;
  return  z.bit16 ;  
}

16bit(2byte)のメモリ領域を
1つの16bit変数として見たり
2つの8bit変数として見たりする例。

同じメモリ領域を bit16で参照したり、
bit8x2のb1、b2で参照したりできます。


32bitスワップ

uint32_t  bswap_32(uint32_t x){
  union   {
    uint32_t  bit32;
    struct    {uint8_t  b1,b2,b3,b4;} bit8x4;  
  } y,z ;
  y.bit32 = x ;
  z.bit8x4.b1 = y.bit8x4.b4;
  z.bit8x4.b2 = y.bit8x4.b3;
  z.bit8x4.b3 = y.bit8x4.b2;
  z.bit8x4.b4 = y.bit8x4.b1;
  return  z.bit32 ;  
}

32bit(4byte)のメモリ領域を
1つの32bit変数として見たり
4つの8bit変数として見たりする例。

bit32とbit8x4を重ねて参照します。


64bitスワップ

uint64_t  bswap_64(uint64_t x){
  union   {
    uint64_t  bit64;
    struct    {uint8_t  b1,b2,b3,b4,b5,b6,b7,b8;} bit8x8;  
  } y,z ;
  y.bit64 = x ;
  z.bit8x8.b1 = y.bit8x8.b8;
  z.bit8x8.b2 = y.bit8x8.b7;
  z.bit8x8.b3 = y.bit8x8.b6;
  z.bit8x8.b4 = y.bit8x8.b5;
  z.bit8x8.b5 = y.bit8x8.b4;
  z.bit8x8.b6 = y.bit8x8.b3;
  z.bit8x8.b7 = y.bit8x8.b2;
  z.bit8x8.b8 = y.bit8x8.b1;
  return  z.bit64 ;  
}

64bit(8byte)のメモリ領域を
1つの64bit変数として見たり
8つの8bit変数として見たりする例。

bit64とbit8x8を重ねて参照します。


union(共用体)を使ったスワップ(まとめ)

#include  <stdio.h>
#include  <stdint.h>
#include  <limits.h> 
//16bit(2byte)をスワップする
uint16_t  bswap_16(uint16_t x){
  union   {
    uint16_t  bit16;
    struct    {uint8_t  b1,b2;} bit8x2;  
  } y,z ;
  y.bit16 = x ;
  z.bit8x2.b1 = y.bit8x2.b2;
  z.bit8x2.b2 = y.bit8x2.b1;
  return  z.bit16 ;  
}
//32bit(4byte)をスワップする
uint32_t  bswap_32(uint32_t x){
  union   {
    uint32_t  bit32;
    struct    {uint8_t  b1,b2,b3,b4;} bit8x4;  
  } y,z ;
  y.bit32 = x ;
  z.bit8x4.b1 = y.bit8x4.b4;
  z.bit8x4.b2 = y.bit8x4.b3;
  z.bit8x4.b3 = y.bit8x4.b2;
  z.bit8x4.b4 = y.bit8x4.b1;
  return  z.bit32 ;  
}
//64bit(8byte)をスワップする
uint64_t  bswap_64(uint64_t x){
  union   {
    uint64_t  bit64;
    struct    {uint8_t  b1,b2,b3,b4,b5,b6,b7,b8;} bit8x8;  
  } y,z ;
  y.bit64 = x ;
  z.bit8x8.b1 = y.bit8x8.b8;
  z.bit8x8.b2 = y.bit8x8.b7;
  z.bit8x8.b3 = y.bit8x8.b6;
  z.bit8x8.b4 = y.bit8x8.b5;
  z.bit8x8.b5 = y.bit8x8.b4;
  z.bit8x8.b6 = y.bit8x8.b3;
  z.bit8x8.b7 = y.bit8x8.b2;
  z.bit8x8.b8 = y.bit8x8.b1;
  return  z.bit64 ;  
}
int main(void){
  for(uint64_t i = 0x0123456789abcdef  ; i != 0; i >>= 4){
    uint16_t u16 = i;
    uint32_t u32 = i;
    uint64_t u64 = i; 
    printf("%04X -> %04X\t",     u16, bswap_16(u16));
    printf("%08X -> %08X\t",     u32, bswap_32(u32));
    printf("%016lX -> %016lX\n", u64, bswap_64(u64));
  }
}

●実行例

CDEF -> EFCD	89ABCDEF -> EFCDAB89	0123456789ABCDEF -> EFCDAB8967452301
BCDE -> DEBC	789ABCDE -> DEBC9A78	00123456789ABCDE -> DEBC9A7856341200
ABCD -> CDAB	6789ABCD -> CDAB8967	000123456789ABCD -> CDAB896745230100
9ABC -> BC9A	56789ABC -> BC9A7856	0000123456789ABC -> BC9A785634120000
89AB -> AB89	456789AB -> AB896745	00000123456789AB -> AB89674523010000
789A -> 9A78	3456789A -> 9A785634	000000123456789A -> 9A78563412000000
6789 -> 8967	23456789 -> 89674523	0000000123456789 -> 8967452301000000
5678 -> 7856	12345678 -> 78563412	0000000012345678 -> 7856341200000000
4567 -> 6745	01234567 -> 67452301	0000000001234567 -> 6745230100000000
3456 -> 5634	00123456 -> 56341200	0000000000123456 -> 5634120000000000
2345 -> 4523	00012345 -> 45230100	0000000000012345 -> 4523010000000000
1234 -> 3412	00001234 -> 34120000	0000000000001234 -> 3412000000000000
0123 -> 2301	00000123 -> 23010000	0000000000000123 -> 2301000000000000
0012 -> 1200	00000012 -> 12000000	0000000000000012 -> 1200000000000000
0001 -> 0100	00000001 -> 01000000	0000000000000001 -> 0100000000000000