C++ POSIX cksum和Boost.CRC

C++ POSIX cksum和Boost.CRC,c++,boost,posix,crc,C++,Boost,Posix,Crc,我正在尝试使用Boost.CRC实现简单的POSIXcksum 我使用的代码相当于: 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(buff

我正在尝试使用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]);
}
作为唯一的32位CRC类型定义。对于空文件(
touch test&&cksum test
),它给出了错误的答案(使用GNUWin32 coreutils
cksum
)。我尝试过使用上面的typedef并将
0xFFFFFFFF
的一个或两个值修改为0,我得到了一个空文件的正确结果,但任何其他文件仍会给出不同的结果


Boost.CRC与这个问题有什么关系?

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

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

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_32_type;
这是因为:

  • 规范未指定生成器的起始值,因此为0
  • 输出值应根据规范第4条进行补充。通过将值与1进行XOR运算,可以获得相同的结果
  • 在任何地方都没有提到位反射,因此不会执行
然而,与普通CRC相比,
cksum
有一个显著的区别:

(…)后接一个或多个八位字节,表示 文件作为二进制值,最不重要的八位字节优先。最小的 应使用能够表示该整数的八位字节数

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

不幸的是,我看不到解决这个问题的简单方法。我想您可以通过以下方式修改
process\u 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];
}
模板
内联
无效的
BOOST\u CRC\u最佳\u名称::进程\u字节
(
无效常量*缓冲区,
std::大小\u t字节\u计数
)
{
无符号字符常量*常量b=静态_转换(
缓冲液);
进程块(b,b+字节计数);
对于(;字节计数;字节计数>>=8)
rem=(rem>24)^字节计数)&0xFF];
}
在这种实现中,该方法给出了与
cksum
相同的结果<代码>用于GNU coreutils提供的循环


希望我能帮上忙。

这并不是对你问题的回答,而是我进行的调查结果。当我用VHDL构建一个简单的以太网控制器实现时,我常常与CRC作斗争,我意识到由于未知的原因,实现有时会有很大的变化

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

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_32_type;
这是因为:

  • 规范未指定生成器的起始值,因此为0
  • 输出值应根据规范第4条进行补充。通过将值与1进行XOR运算,可以获得相同的结果
  • 在任何地方都没有提到位反射,因此不会执行
然而,与普通CRC相比,
cksum
有一个显著的区别:

(…)后接一个或多个八位字节,表示 文件作为二进制值,最不重要的八位字节优先。最小的 应使用能够表示该整数的八位字节数

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

不幸的是,我看不到解决这个问题的简单方法。我想您可以通过以下方式修改
process\u 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];
}
模板
内联
无效的
BOOST\u CRC\u最佳\u名称::进程\u字节
(
无效常量*缓冲区,
std::大小\u t字节\u计数
)
{
无符号字符常量*常量b=静态_转换(
缓冲液);
进程块(b,b+字节计数);
对于(;字节计数;字节计数>>=8)
rem=(rem>24)^字节计数)&0xFF];
}
在这种实现中,该方法给出了与
cksum
相同的结果<代码>用于GNU coreutils提供的循环


希望我能帮上忙。

这就是我如此热爱的原因。感谢您的详细分析。我想写一个小的包装函数来实现这一点,并调用
crc.process\u block
是不修改Boost代码的最佳解决方案。当然,我想这也行。但是您需要访问用于计算它的CRC表,并且它被声明为私有:(也许您可以为
cksum
CRC生成器编写一个模板专门化,它将有自己的
process\u block
实现?啊,是的,模板专门化可以工作。希望我只需要实现
process\u block
:).您有一些变量,如起始值和补码位置/是否补码。玩这些游戏通常相当快。我的初始CRC为0xFFFFFF的测试文件给出的CRC为0x2B4F35FE,这是错误的,但我将初始值更改为0,得到的0x92E04DBC是正确的。这是一个由四个部分组成的部分,在你交换一些数字之前,不要想太多。这不是我第一次看到这种情况发生。这就是为什么我如此喜欢它。谢谢你的详细介绍