バイト列から整数を得る

A4906ea02ea1385bf9a8a18eac62c6da?s=47 森建
April 23, 2019

 バイト列から整数を得る

A4906ea02ea1385bf9a8a18eac62c6da?s=128

森建

April 23, 2019
Tweet

Transcript

  1. バイト列から整数を得る fukuoka.rs vol.3 pixiv Inc. 森内 建太 2019.4.23

  2. 2 自己紹介 • 主にフロントエンドエンジニア • Ruby on Rails、iOS アプリ開発もやる •

    ECMAScript とか DOM API とかの仕様まわりを調 べるのが好き 福岡オフィスエンジニア
  3. におけるバイト列 3

  4. 4 • &[u8], &mut [u8], Vec<u8> でバイト列を扱う ◦ 読み込む場合は &mut

    [u8] にしてから Read の実装を使う ◦ Rustでバイト列を扱う時のtips - κeenのHappy Hacκing Blog https://keens.github.io/blog/2016/12/01/rustdebaitoretsuwoatsukautokinotips/ におけるバイト列
  5. バイト列の読み込み 5 use std::io::{Read as _, Result}; fn main() ->

    Result<()> { let mut bytes: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]; let mut buf = [0; 4]; bytes.read_exact(&mut buf)?; println!("{:#x?}", buf); // [0x12, 0x34, 0x56, 0x78] assert_eq!(bytes.len(), 2); Ok(()) }
  6. マルチバイト型への変換 6

  7. 7 • &mut [u8] でバイト列を扱うため、u32 にしたい場合は変換しなければならない ◦ std::mem::transmute を使って [u8;

    4] を u32 にする マルチバイト型への変換 use std::io::{Read as _, Result}; use std::mem::transmute; fn main() -> Result<()> { let mut bytes: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]; let mut buf = [0; 4]; bytes.read_exact(&mut buf)?; let val = unsafe { transmute::<[u8; 4], u32>(buf) }; println!("{}", val); Ok(()) }
  8. ところで 8 use std::io::{Read as _, Result}; use std::mem::transmute; fn

    main() -> Result<()> { let mut bytes: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]; let mut buf = [0; 4]; bytes.read_exact(&mut buf)?; let val = unsafe { transmute::<[u8; 4], u32>(buf) }; assert_eq!(val, 0x78563412); // ??? Ok(()) }
  9. 9 • CPU によってマルチバイトな型において メモリに置かれる順序が異なる ◦ ビッグエンディアンなら 0x12345678 ◦ リトルエンディアンなら

    0x78563412 • つまりビッグエンディアンなバイト列をリトルエンディアン環境で読み込むなら 順序を並び替える必要がある ◦ Rust の条件付きコンパイルで環境のエンディアンを判定できる ◦ cfg(target_endianess = “little”) エンディアン
  10. エンディアンの変換 10 let raw = unsafe { transmute::<[u8; 4], u32>([0x12,

    0x34, 0x56, 0x78]) }; let val = if cfg!(target_endianess = "little") { raw.swap_bytes() } else { raw }; assert_eq!(val, 0x12345678); let raw = unsafe { transmute::<[u8; 4], u32>([0x12, 0x34, 0x56, 0x78]) }; let val = u32::from_be(raw); assert_eq!(val, 0x12345678);
  11. まとめると 11 use std::io::{Read as _, Result}; use std::mem::transmute; fn

    main() -> Result<()> { let mut bytes: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]; let mut buf = [0; 4]; bytes.read_exact(&mut buf)?; let raw = unsafe { transmute::<[u8; 4], u32>(buf) }; let val = u32::from_be(raw); assert_eq!(val, 0x12345678); Ok(()) }
  12. 12

  13. 13 • 今まで説明したやつをまるまるやってくれる便利なクレート ◦ use byteorder::ReadBytesExt で Read を拡張する とは

    use std::io::Result; use byteorder::{BigEndian, ReadBytesExt as _}; fn main() -> Result<()> { let mut bytes: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]; let val = bytes.read_u32::<BigEndian>()?; assert_eq!(val, 0x12345678); Ok(()) }
  14. 14 • Rust でバイト列を読み込むには &mut [u8] の Read を使う ◦

    Rustでバイト列を扱う時のtips - κeenのHappy Hacκing Blog https://keens.github.io/blog/2016/12/01/rustdebaitoretsuwoatsukautokinotips/ • マルチバイト型への変換時にエンディアンを考慮する必要がある • byteorder クレートが便利! まとめ