为什么这个CRC不是2字节字符串?

时间:2014-05-23 09:24:30

标签: python binary crc

使用此字符串“000016037000”和此CRC16函数,结果不是2字节字符串,为什么会这样?

def _crc16(data, bits=8):
    """private method: for calculating the CRC
    based on the standard EN50463-4

    Arguments:
        Input: data in ASCII encoding !
        Output: CRC of the data
    """
    crc = 0xFFFF
    for l in list(data):
        """or exclusive
        bin: gives the binary representation
        int: cast the string to an int with the base2
        ord: gives the ASCII code for the caracter between (0..255)
        """
        crc = crc ^ int(bin(ord(l)), 2)
        for bit in range(0, bits):
            if (crc & 0x0001) == 0x0001:
                crc = ((crc >> 1) ^ 0xA001)
            else:
                crc = crc >> 1

    return _typecasting(crc)


def _typecasting(crc):
    """gives the msb and lsb"""
    msb = hex(crc >> 8)
    lsb = hex(crc & 0x00FF)

    return lsb + msb

data = "000016037000"

print _crc16(data)

这是结果:0x00xfc,当你剥离'0x'是0fc! CRC16应该生成2字节的校验和,lsb为0是正常的吗?

3 个答案:

答案 0 :(得分:1)

hex()函数返回前面带有0x的字符串。因此,在typecasting函数中,您有:

lsb = "0x00"
msb = "0xfc"

当你连接它们时,你会在前面和中间得到0x。在连接之前,您应该从0x删除msb

return lsb + msb[2:]

然后你会得到0x00fc

答案 1 :(得分:1)

是的,这很正常。就像0中的10一样。顺便说一句,你的主循环有点过于冗长,如何:

crc = 0xFFFF
for l in data:
    crc ^= ord(l)
    for bit in range(0, bits):
        if crc & 1:
            crc = (crc >> 1) ^ 0xA001
        else:
            crc >>= 1

似乎交换lsb和msb的typecasting函数可以更简洁地编写为

def byteswap(crc):    
    return (crc >> 8) | (crc & 0x00FF) << 8

请注意,为避免麻烦,两个函数都只能使用整数,不需要hexbin

答案 2 :(得分:1)

你似乎有不少不必要的转换,问题是关于其中一个效果。我将尝试按执行顺序解释它们。

for l in list(data):

在这里,您将字符串转换为字母列表,每个字母本身都是一个字符串(Python不使用char数据类型)。这个工作的原因是因为你可以迭代字符串本身;只需删除list()调用。

    crc = crc ^ int(bin(ord(l)), 2)

作为旁注,ord()实际上得到了序号;它不一定是ASCII(事实上,没有代码&gt; 127是ASCII)。一旦我们有了这个数字,你就把它转换为二进制和后面的文本表示;配对,两次转换都是多余的。

msb = hex(crc >> 8)
lsb = hex(crc & 0x00FF)
return lsb + msb

每次调用hex()都会转换为十六进制表示形式。与bin()一样,这是Python数字文字的形式,因此它们每个都以0x为前缀。连接它们产生一种有点奇怪的格式(虽然仍然可以恢复,但它不像任何常见的格式)。在这一点上,知道你的目标可能会很好。

一个猜测是你需要一个4位十六进制格式的小端16位无符号整数(面向字节的hexdump)。我们可以使用Python的标准库来表达:

import binascii, struct
le16hex = binascii.b2a_hex(struct.pack('<H', crc))

此处<标记小端,H标记无符号的16位值,b2a_hex从二进制转换为十六进制。如果我们只想要一个4位十六进制值(偶然匹配bigendian形式),我们可以使用"%04x"%crc

但是,您也会问为什么结果不是两个字节的字符串。那是因为你用十六进制要求它;上面的struct.pack只生成一个两字节的字符串。结合您输入的偶数位数,我不禁要问您是否要处理二进制数据(如ord和struct do)或所有十六进制(甚至是八进制)。需要更多的背景来理解这一点。

至于最低有效字节为0,这是该特定字符串的效果;它只显示一位数是因为hex()不会产生超过必要的数字。 %格式化操作可以生成特定的数字位数。