POSIX cksum and Boost.CRC

POSIX cksum and Boost.CRC

本文关键字:CRC Boost and cksum POSIX      更新时间:2023-10-16

我正在尝试使用Boost.CRC实现简单的POSIX cksum

我使用的代码相当于:

for(int i = 1; i<argc; ++i)
{
  support::file current(argv[i], support::file::access::read);
  size_t octets = 0;
  boost::crc_32_type crc;
  while(true)
  {
    size_t bytes_read = current.read_some(buffer_size, buffer);
    octets += bytes_read;
    crc.process_bytes(&buffer[0], bytes_read);
    if(bytes_read < buffer_size)
      break;
  }
  if(i>1)
    support::print("n");
  support::print(boost::lexical_cast<string>(crc.checksum()) + " " + boost::lexical_cast<string>(octets) + " " + argv[i]);
}

其中support::file是一个简单的fopen/fread二进制文件I/O包装器,我成功地用于cat实现。support::print给出与std::cout相同的输出,但我需要它在Windows上可靠的非ascii输出。

Boost头有这个:

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_32_type;

作为唯一的32位CRC类型定义。对于一个空文件(touch test && cksum test),它给出了错误的答案(用GNUWin32 coretils cksum检查)。我已经尝试使用上面的typedef并将0xFFFFFFFF值中的一个或两个修改为0,我得到了空文件的正确结果,但任何其他文件仍然给出了不同的结果。

如何提高。与POSIX cksum规范相关的CRC ?

这不是你问题的答案,而是我进行的调查的结果。当我在VHDL中构建以太网控制器的简单实现时,我曾经与CRC作斗争,并且我意识到实现有时可能由于未知的原因而变化很大。

好的,我们开始吧。您在boost/crc.hpp中找到的typedef:

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_32_type;

是一个简单的CRC生成器声明,它将为以太网生成CRC。模板的参数如下:Bits(由发电机输出的比特数),TruncPoly(使用的多项式发电机),InitRem(最初的剩余送入算法在处理之前输入的第一个字节),FinalXor(输出值的值应该XORed之后处理所有输入的字节),ReflectInReflectRem(如果输入字节和/或输出应该bit-reflected,例如一点一点0变成7,等等)。以太网不仅要求使用给定的多项式计算输出,而且还要求可以从该typedef中读取约束。

根据cksum的规范,它的CRC生成器的类型定义应该像这样:

typedef crc_optimal<32, 0x04C11DB7, 0, 0xFFFFFFFF, false, false> cksum_crc_type;

这是因为:

  • 规范没有指定生成器的起始值,因此为0。
  • 输出值应按规范第4条补充。同样的结果也可以通过将值与1相乘来实现。
  • 位反射在任何地方都没有提到,因此不会执行。

然而,与普通crc相比,cksum有一个显著的区别:

(…)后跟一个或多个八位元组,表示字符的长度文件作为二进制值,最低有效位优先。最小的应使用能够表示该整数的八位字节数。

普通的CRC生成器不考虑被处理的字节数。这也解释了为什么在处理零长度文件时会得到好的结果,而在处理较大的文件时会得到不好的结果。

不幸的是,我找不到一个简单的解决方案。我猜你能做的是修改process_bytes方法在以下方式:

template < std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly,
           BOOST_CRC_PARM_TYPE InitRem, BOOST_CRC_PARM_TYPE FinalXor,
           bool ReflectIn, bool ReflectRem >
inline
void
BOOST_CRC_OPTIMAL_NAME::process_bytes
(
    void const *   buffer,
    std::size_t  byte_count
)
{
    unsigned char const * const  b = static_cast<unsigned char const *>(
     buffer );
    process_block( b, b + byte_count );
    for(; byte_count; byte_count >>= 8)
        rem_ = (rem_ << 8) ^ crc_table_type::table_[((rem_ >> 24) ^ byte_count) & 0xFF];
}

通过这样的实现,该方法给出了与cksum相同的结果。for循环由GNU coretils提供。

希望我帮到你。