C言語でバイトオーダーの交換(バイトスワップ)方法を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
C言語でバイトオーダーの交換(バイトスワップ)
C言語でバイトオーダーの交換(バイトスワップ)方法を紹介します.
バイトスワップはOSで利用されるので使いこなせるようにしましょう.
また,x86-64でビット演算を行う命令も紹介しますので,C言語の実装と比較してみましょう.
ビット演算を基本から学びたいあなたはこちらを読むことをおすすめします.
整数のバイトスワップ
整数のバイトスワップ方法を3つ紹介します.
あなたの実行環境で動作する方法を利用しましょう!
bswap_16/bswap_32/bswap_64関数
1 2 3 |
uint16_t bswap_16(uint16_t x); uint32_t bswap_32(uint32_t x); uint64_t bswap_64(uint64_t x); |
byteswap.hのbswap_16/bswap_32/bswap_64関数(マクロ実装の場合もあり)を利用するコードは以下になります.
bswap_16/bswap_32/bswap_64関数はGNU拡張なのでGCC/Clangでは利用できますが,Visual Studioでは利用できないことに注意して下さい.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> #include <byteswap.h> int main(void) { uint16_t u16; uint32_t u32; uint64_t u64; printf("Please input a 16-bit unsigned integer: 0x"); scanf("%hx", &u16); printf("bswap_16(0x%hx) = 0x%hx\n", u16, bswap_16(u16)); printf("Please input a 32-bit unsigned integer: 0x"); scanf("%x", &u32); printf("bswap_32(0x%x) = 0x%x\n", u32, bswap_32(u32)); printf("Please input a 32-bit unsigned integer: 0x"); scanf("%lx", &u64); printf("bswap_64(0x%lx) = 0x%lx\n", u64, bswap_64(u64)); return 0; } |
実行結果は以下になります.
数値は16進数で入力していることに注意して下さい.
また,数字1文字につき4ビット,2文字で8ビット(1バイト)になります.
- 3行目の行末で「1234」を入力したら4行目の行末で「0x3412」と表示
- 5行目の行末で「12345678」を入力したら6行目の行末で「0x78563412」と表示
- 7行目の行末で「0x1234567890abcdef」を入力したら8行目の行末で「0xefcdab9078563412」と表示
1 2 3 4 5 6 7 8 |
$ gcc byteswap.c $ a.out Please input a 16-bit unsigned integer: 0x1234 bswap_16(0x1234) = 0x3412 Please input a 32-bit unsigned integer: 0x12345678 bswap_32(0x12345678) = 0x78563412 Please input a 32-bit unsigned integer: 0x1234567890abcdef bswap_64(0x1234567890abcdef) = 0xefcdab9078563412 |
bswap_16/bswap_32/bswap_64関数の自作関数
bswap_16/bswap_32/bswap_64関数の自作関数「mybswap_16/mybswap_32/mybswap_64関数」のコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> uint16_t mybswap_16(uint16_t x) { return ((uint16_t)((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))); } uint32_t mybswap_32(uint32_t x) { return ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)); } uint64_t mybswap_64(uint64_t x) { return ((((x) & 0xff00000000000000ull) >> 56) \ | (((x) & 0x00ff000000000000ull) >> 40) \ | (((x) & 0x0000ff0000000000ull) >> 24) \ | (((x) & 0x000000ff00000000ull) >> 8) \ | (((x) & 0x00000000ff000000ull) << 8) \ | (((x) & 0x0000000000ff0000ull) << 24) \ | (((x) & 0x000000000000ff00ull) << 40) \ | (((x) & 0x00000000000000ffull) << 56)); } int main(void) { uint16_t u16; uint32_t u32; uint64_t u64; printf("Please input a 16-bit unsigned integer: 0x"); scanf("%hx", &u16); printf("mybswap_16(0x%hx) = 0x%hx\n", u16, mybswap_16(u16)); printf("Please input a 32-bit unsigned integer: 0x"); scanf("%x", &u32); printf("mybswap_32(0x%x) = 0x%x\n", u32, mybswap_32(u32)); printf("Please input a 32-bit unsigned integer: 0x"); scanf("%lx", &u64); printf("mybswap_64(0x%lx) = 0x%lx\n", u64, mybswap_64(u64)); return 0; } |
実行結果は以下になります.同様です.
1 2 3 4 5 6 7 8 |
$ gcc mybyteswap.c $ a.out Please input a 16-bit unsigned integer: 0x1234 mybswap_16(0x1234) = 0x3412 Please input a 32-bit unsigned integer: 0x12345678 mybswap_32(0x12345678) = 0x78563412 Please input a 32-bit unsigned integer: 0x1234567890abcdef mybswap_64(0x1234567890abcdef) = 0xefcdab9078563412 |
x86-64のrolw/bswap命令
x86-64のrolw/bswap命令を利用するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> static inline uint16_t rolw(uint16_t x) { uint16_t ret = x; asm volatile("rolw $8, %0" : "=r"(ret)); return ret; } static inline uint32_t bswap32(uint32_t x) { uint32_t ret = x; asm volatile("bswap %0": "=r"(ret)); return ret; } static inline uint64_t bswap64(uint64_t x) { uint64_t ret = x; asm volatile("bswap %0": "=r"(ret)); return ret; } int main(void) { uint16_t u16; uint32_t u32; uint64_t u64; printf("Please input a 16-bit unsigned integer: 0x"); scanf("%hx", &u16); printf("rolw(0x%hx) = 0x%hx\n", u16, rolw(u16)); printf("Please input a 32-bit unsigned integer: 0x"); scanf("%x", &u32); printf("bswap32(0x%x) = 0x%x\n", u32, bswap32(u32)); printf("Please input a 32-bit unsigned integer: 0x"); scanf("%lx", &u64); printf("bswap64(0x%lx) = 0x%lx\n", u64, bswap64(u64)); return 0; } |
実行結果は以下になります.同様です.
1 2 3 4 5 6 7 8 |
$ gcc rolw_and_bswap.c $ a.out Please input a 16-bit unsigned integer: 0x1234 rolw(0x1234) = 0x3412 Please input a 32-bit unsigned integer: 0x12345678 bswap32(0x12345678) = 0x78563412 Please input a 32-bit unsigned integer: 0x1234567890abcdef bswap64(0x1234567890abcdef) = 0xefcdab9078563412 |
浮動小数点数のバイトスワップ
浮動小数点数のバイトスワップ方法を紹介します.
共用体を使うと簡単に実装できます.
共用体を学びたいあなたはこちらからどうぞ.
浮動小数点数をバイトスワップするコードは以下になります.
mybswap_32/mybswap_64関数を利用しています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdint.h> union ufloat { float f; uint8_t s[sizeof(float)]; uint32_t u; }; union udouble { double d; uint8_t s[sizeof(double)]; uint64_t u; }; uint32_t mybswap_32(uint32_t x) { return ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)); } uint64_t mybswap_64(uint64_t x) { return ((((x) & 0xff00000000000000ull) >> 56) \ | (((x) & 0x00ff000000000000ull) >> 40) \ | (((x) & 0x0000ff0000000000ull) >> 24) \ | (((x) & 0x000000ff00000000ull) >> 8) \ | (((x) & 0x00000000ff000000ull) << 8) \ | (((x) & 0x0000000000ff0000ull) << 24) \ | (((x) & 0x000000000000ff00ull) << 40) \ | (((x) & 0x00000000000000ffull) << 56)); } void print_ufloat(union ufloat uf) { int i; for (i = 0; i < sizeof(float); i++) { printf("%02x ", uf.s[i]); } printf("\n"); } void print_udouble(union udouble ud) { int i; for (i = 0; i < sizeof(double); i++) { printf("%02x ", ud.s[i]); } printf("\n"); } int main(void) { union ufloat uf; union udouble ud; printf("Please input a floating point number: "); scanf("%f", &uf.f); print_ufloat(uf); uf.u = mybswap_32(uf.u); print_ufloat(uf); printf("Please input a double floating point number: "); scanf("%lf", &ud.d); print_udouble(ud); ud.u = mybswap_64(ud.u); print_udouble(ud); return 0; } |
実行結果は以下になります.
正しくバイトスワップできていることがわかります.
私の実行環境のIntel CPUでは,リトルエンディアンでバイトデータを格納していることに注意して下さい.
1 2 3 4 5 6 7 8 |
$ gcc myfpbyteswap.c $ a.out Please input a floating point number: 1.0 00 00 80 3f 3f 80 00 00 Please input a double floating point number: 1.0 00 00 00 00 00 00 f0 3f 3f f0 00 00 00 00 00 00 |
まとめ
C言語でバイトオーダーの交換(バイトスワップ)方法を整数と浮動小数点数で紹介しました.
3つの方法がありますので,あなたの実行環境で動作する方法を利用しましょう!
ビット演算とシフト演算の応用を学びたいあなたはこちらからどうぞ.
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!