Upgrade to Pro — share decks privately, control downloads, hide ads and more …

バイト列から整数を得る

森建
April 23, 2019

 バイト列から整数を得る

森建

April 23, 2019
Tweet

More Decks by 森建

Other Decks in Programming

Transcript

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

    View Slide

  2. 2
    自己紹介
    ● 主にフロントエンドエンジニア
    ● Ruby on Rails、iOS アプリ開発もやる
    ● ECMAScript とか DOM API とかの仕様まわりを調
    べるのが好き
    福岡オフィスエンジニア

    View Slide

  3. におけるバイト列
    3

    View Slide

  4. 4
    ● &[u8], &mut [u8], Vec でバイト列を扱う
    ○ 読み込む場合は &mut [u8] にしてから Read の実装を使う
    ○ Rustでバイト列を扱う時のtips - κeenのHappy Hacκing Blog
    https://keens.github.io/blog/2016/12/01/rustdebaitoretsuwoatsukautokinotips/
    におけるバイト列

    View Slide

  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(())
    }

    View Slide

  6. マルチバイト型への変換
    6

    View Slide

  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(())
    }

    View Slide

  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(())
    }

    View Slide

  9. 9
    ● CPU によってマルチバイトな型において
    メモリに置かれる順序が異なる
    ○ ビッグエンディアンなら 0x12345678
    ○ リトルエンディアンなら 0x78563412
    ● つまりビッグエンディアンなバイト列をリトルエンディアン環境で読み込むなら
    順序を並び替える必要がある
    ○ Rust の条件付きコンパイルで環境のエンディアンを判定できる
    ○ cfg(target_endianess = “little”)
    エンディアン

    View Slide

  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);

    View Slide

  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(())
    }

    View Slide

  12. 12

    View Slide

  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::()?;
    assert_eq!(val, 0x12345678);
    Ok(())
    }

    View Slide

  14. 14
    ● Rust でバイト列を読み込むには &mut [u8] の Read を使う
    ○ Rustでバイト列を扱う時のtips - κeenのHappy Hacκing Blog
    https://keens.github.io/blog/2016/12/01/rustdebaitoretsuwoatsukautokinotips/
    ● マルチバイト型への変換時にエンディアンを考慮する必要がある
    ● byteorder クレートが便利!
    まとめ

    View Slide