首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >逐字计算CRC

逐字计算CRC
EN

Code Review用户
提问于 2016-05-22 15:04:17
回答 1查看 535关注 0票数 8

这是一个小程序,用于计算STM32程序映像的CRC,与STM32硬件上的CRC兼容。它是一个逐字的CRC,bin文件被编码成一系列32位的小endian字。

这是我第一次认真地尝试Rust,我想征求一些一般性意见,以及几个问题:

  • 在构建单词时,是否有更好的编写重复(buff[3] as u32)的方法?
  • T: Read特征界限应该去哪里?他们也应该上WordIterator吗?
代码语言:javascript
复制
use std::fs::File;
use std::io::Read;

struct WordIterator<T> {
    rd: T
}

impl<T: Read> WordIterator<T> {
    fn new(f: T) -> WordIterator<T> {
        WordIterator {rd: f}
    }
}

impl<T: Read> Iterator for WordIterator<T> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        let mut buf = [0 as u8; 4];
        match self.rd.read(&mut buf) {
            Ok(4) => {
                let v: u32 = (buf[3] as u32) << 24 |
                (buf[2] as u32) << 16 |
                (buf[1] as u32) << 8  |
                (buf[0] as u32) << 0;

                Some( v )
            },
            _ => {
                None
            }
        }
    }
}

struct CrcCalculator {
    lookup_table: [u32; 256]
}

impl CrcCalculator {
    fn new() -> CrcCalculator {
        let mut calc = CrcCalculator {lookup_table: [0; 256]};

        // Calculate the table:
        for v in 0..256 {
            let mut v2: u32 = v << 24;
            for _ in 0..8 {
                if 0 != v2 & 0x80000000 {
                    v2 = (v2 << 1) ^ 0x04C11DB7;
                }
                else {
                    v2 = v2 << 1;
                }
            }

            calc.lookup_table[v as usize] = v2;
        }

        calc
    }

    fn calculate<T: Read>(&self, f: T) -> (u32, u32) {
        let mut crc: u32 = 0xFFFFFFFF;
        let mut count = 0;

        for word in WordIterator::new(f) {
            crc = crc ^ word;
            crc = (crc << 8) ^ self.lookup_table[((crc >> 24) & 0xFF) as usize];
            crc = (crc << 8) ^ self.lookup_table[((crc >> 24) & 0xFF) as usize];
            crc = (crc << 8) ^ self.lookup_table[((crc >> 24) & 0xFF) as usize];
            crc = (crc << 8) ^ self.lookup_table[((crc >> 24) & 0xFF) as usize];

            count += 1;
        }

        (count, crc)
    }
}

fn main() {
    let lt = CrcCalculator::new();

    let f = File::open("Image.bin").unwrap();
    let (count, crc) = lt.calculate(f);

    println!("count=0x{:X} crc=0x{:08X}", count, crc);
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-05-22 16:41:13

总的来说,这看起来很合理!在struct声明中有一些类似于小样式nits的空格。更重要的一点是:

  1. 铁锈社区喜欢板条箱和重用现有的工作。在这种情况下,您应该使用字节顺序,而不是自作主张。除了更少的代码,一个很好的好处是,您现在使用的是在代码中用文字编写的小endian!
  2. 如果您做这个项目不是为了好玩或学习,我建议您使用一个现有的CRC板条箱来完全避免重新发明轮子!
  3. 考虑将查找表设置为懒惰_静态全局表。这将允许只初始化一次。
  4. 更好的是,考虑硬编码查找表。这将使您能够避免任何创建开销。有两条路径:
    1. 你可以把它复制粘贴进去。可能不错,因为CRC表不太可能经常改变。
    2. 创建一个在编译时生成它的构建脚本,然后包含结果。这在构建时有一些开销,但是捕获了用于生成表的过程。

  5. 在不需要类型规范的情况下,还有一些额外的地方,例如在构建表时。如果可能的话,最好允许推理应用。因为您在usizeu32之间来回切换,所以仍然需要一些地方。
  6. 您可以为重复的位洗牌提取函数和/或使用循环。如果您关心性能,您可能希望对其进行概要分析,因为有时仍然需要手动循环展开。
  7. 使用expect而不是展开,以帮助您和您的用户理解失败。
  8. 在文件读取中添加一些缓冲,以防止低效的系统调用。
  9. 尝试命名您的泛型类型,以便名称提示类型。当类型基本上可以是任何类型时,T是很棒的,但在本例中,我建议R来反映Read绑定。
  10. 对变量名进行一些扩展。rd具有更大的范围,因为它在多个位置之间共享,应该有一个更简单的名称。
  11. 我更喜欢使用where子句来指定特征界限。我觉得更容易读懂。
  12. 我只在函数实现需要的情况下添加特征边界。
代码语言:javascript
复制
extern crate byteorder;

use byteorder::{LittleEndian, ReadBytesExt};

use std::fs::File;
use std::io::{Read, BufReader};

struct WordIterator<R> {
    inner: R,
}

impl<R> WordIterator<R> {
    fn new(r: R) -> WordIterator<R> {
        WordIterator { inner: r }
    }
}

impl<R> Iterator for WordIterator<R>
    where R: Read,
{
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        self.inner.read_u32::<LittleEndian>().ok()
    }
}

struct CrcCalculator {
    lookup_table: [u32; 256],
}

impl CrcCalculator {
    fn new() -> CrcCalculator {
        let mut calc = CrcCalculator { lookup_table: [0; 256] };

        // Calculate the table:
        for v in 0..256 {
            let mut v2 = v << 24;
            for _ in 0..8 {
                if 0 != v2 & 0x80000000 {
                    v2 = (v2 << 1) ^ 0x04C11DB7;
                } else {
                    v2 = v2 << 1;
                }
            }

            calc.lookup_table[v as usize] = v2;
        }

        calc
    }

    fn calculate<R>(&self, r: R) -> (u32, u32)
        where R: Read,
    {
        let mut crc = 0xFFFFFFFF;
        let mut count = 0;

        for word in WordIterator::new(r) {
            crc = crc ^ word;

            for _ in 0..4 {
                crc = (crc << 8) ^ self.next_component(crc);
            }

            count += 1;
        }

        (count, crc)
    }

    fn next_component(&self, crc: u32) -> u32 {
        self.lookup_table[((crc >> 24) & 0xFF) as usize]
    }
}

fn main() {
    let calculator = CrcCalculator::new();

    let f = BufReader::new(File::open("Image.bin").expect("Couldn't open input file"));
    let (count, crc) = calculator.calculate(f);

    println!("count=0x{:X} crc=0x{:08X}", count, crc);
}

为了好玩,我想看看编译时构建解决方案会是什么样子。

build.rs

代码语言:javascript
复制
use std::env;
use std::io::{self, Write, BufWriter};
use std::fs::File;
use std::path::Path;

fn write_table<W>(mut w: W) -> io::Result<()>
    where W: Write,
{
    try!(writeln!(w, "static CRC_LOOKUP_TABLE: [u32; 256] = ["));

    for v in 0..256u32 {
        let mut v2 = v << 24;
        for _ in 0..8 {
            if 0 != v2 & 0x80000000 {
                v2 = (v2 << 1) ^ 0x04C11DB7;
            } else {
                v2 = v2 << 1;
            }
        }

        if v % 8 == 0 { try!(write!(w, "    ")) }
        try!(write!(w, "0x{:08X}, ", v2));
        if (v + 1) % 8 == 0 { try!(writeln!(w, "")) }
    }

    writeln!(w, "];")
}

fn main() {
    let out_dir = env::var("OUT_DIR").expect("Could not determine where to place output");
    let dest_path = Path::new(&out_dir).join("lookup_table.rs");
    let f = File::create(&dest_path).expect("Could not create lookup table file");
    let f = BufWriter::new(f);
    write_table(f).expect("Could not write lookup table")
}

这意味着CRC函数不再需要是实例方法,而且可以是空闲函数:

代码语言:javascript
复制
include!(concat!(env!("OUT_DIR"), "/lookup_table.rs"));

fn crc_next_component(crc: u32) -> u32 {
    CRC_LOOKUP_TABLE[((crc >> 24) & 0xFF) as usize]
}

fn crc<R>(r: R) -> (u32, u32)
    where R: Read,
{
    let mut crc = 0xFFFFFFFF;
    let mut count = 0;

    for word in WordIterator::new(r) {
        crc = crc ^ word;

        for _ in 0..4 {
            crc = (crc << 8) ^ crc_next_component(crc);
        }

        count += 1;
    }

    (count, crc)
}
票数 7
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/129027

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档