如何计算具有不同数据类型的结构的校验和?

问题描述 投票:-1回答:1

我需要使用此标头填充二进制文件。标头的校验和将添加到标头的末尾。校验和应为1字节总和]

typedef struct {
    uint32 startAddress;
    uint16 size;
    uint32 EndAddress;
    uint8 type;
    uint8 version;
    uint16 modelNo;
    uint8 checksum;
    uint8 reserved[32];
}
c binary embedded checksum automotive
1个回答
0
投票

事实并非是结构包含不同的数据类型,这才是真正的问题-您可以将需要校验和的对象的地址强制转换为uint8*并将其视为字节数组。

您的实际问题是,编译器可以自由地以实现定义的方式对齐成员,并在成员之间插入填充以强制进行对齐。填充字节的值是不确定的,但校验和将包括它们,从而使它们在实例之间不可比较。

简单的解决方案是重写自然对齐方式,并通过编译器提供的任何方式“打包”结构。这对于严重限制资源的系统是有好处的,但并不总是合适的。您可以考虑使用一个序列化函数,在该函数中将成员分别复制到一个字节数组,然后对它进行校验和。但是,与编译器打包相比,序列化需要占用大量资源和处理器,并且可能容易出错和维护开销。

打包和序列化的替代方法可能是使用memset()初始化每个此类对象的整个结构空间,以便填充将具有已知的零值,但是如果您有多个值,则也很难维护和执行这样的对象。

因此,总而言之,您决定以任何方式打包此结构(编译器不同地支持__attribute__ or#pragma`或什至是全局编译器选项。然后,您可能会重新考虑结构设计以从校验和和有效载荷中拆分头:

typedef struct 
{
    uint32 startAddress;
    uint16 size;
    uint32 EndAddress;
    uint8 type;
    uint8 version;
    uint16 modelNo;
} __attribute__((__packed__)) sHeader ;

typedef struct
{
    sHeader header ;
    uint8 checksum;
    uint8 reserved[32];
} __attribute__((__packed__)) sInfo ;

然后给出:

sInfo some_info = ... ;

然后:

info.checksum = 0 ;
for( int i = 0; i < sizeof(some_info .header); i++ )
{
    info.checksum +=  ((uint8*)(&some_info.header))[i] ;
}

如果选择继续使用现有结构,则情况会稍微复杂一些:

typedef struct 
{
    uint32 startAddress;
    uint16 size;
    uint32 EndAddress;
    uint8 type;
    uint8 version;
    uint16 modelNo;
    uint8 checksum;
    uint8 reserved[32];
} __attribute__((__packed__)) sInfo ;

sInfo some_info = ... ;

然后:

ptrdiff_t header_length = (uint8*)(&some_info.checksum) - (uint8*)(&some_info) ;

info.checksum = 0 ;
for( int i = 0; i < header_length; i++ )
{
    info.checksum +=  ((uint8*)(&some_info.header))[i] ;
}

[第二种方法,而且更容易出错,它使用了运行时计算头的大小,而不是第一种的编译时间sizeof()

© www.soinside.com 2019 - 2024. All rights reserved.