在计算 C 结构的校验和时,是否有一种通用方法可以跳过/避免对齐填充字节?
我想通过对字节求和来计算结构的校验和。问题是,该结构具有对齐填充字节,可以获取随机(未指定)值并导致具有相同数据的两个结构获得不同的校验和值。
注意:我主要关心可维护性(添加/删除/修改字段而不需要更新代码)和可重用性,而不是可移植性(平台非常具体且不太可能更改)。
目前,我找到了一些解决方案,但它们都有缺点:
- 打包结构(例如
#pragma pack (1)
)。缺点:我更愿意避免打包以获得更好的性能。 - 逐字段计算校验和。缺点:修改结构时需要更新代码,需要更多代码(取决于字段数)。
- 在设置值之前将所有结构字节设置为零。缺点:我不能完全保证所有结构最初都为零。
- 排列结构字段以避免填充,并可能添加虚拟字段来填充填充。缺点:不通用,在修改结构时需要仔细重新排列结构。
有没有更好的通用方式?
计算校验和示例:
unsigned int calcCheckSum(MyStruct* myStruct)
{
unsigned int checkSum = 0;
unsigned char* bytes = (unsigned char*)myStruct;
unsigned int byteCount = sizeof(MyStruct);
for(int i = 0; i < byteCount; i++)
{
checkSum += bytes[i];
}
return checkSum;
}
最佳答案
Is there a generic way to skip/avoid alignment padding bytes when calculating the checksum of a C struct?
没有严格符合程序可以依赖的机制。这是从
事实是,C 实现被允许在任何一个或多个成员之后布置具有任意填充的结构,无论出于任何原因或无原因,以及
事实是
When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.
( C2011, 6.2.6.1/6 )
前者意味着标准没有提供一致的方式来保证结构布局不包含填充,后者意味着原则上,您无法控制填充字节的值——即使您最初零填充一个结构实例,一旦您分配给该对象或其任何成员,任何填充都会采用不确定的值。
在实践中,您在问题中提到的任何方法都可能在 C 实现和数据性质允许的情况下完成工作。但是只有 (2),逐个成员计算校验和,可以被严格符合的程序使用,并且那个不是“通用的”,因为我认为你是指那个术语。 这是我会选择的。如果您有许多需要校验和的不同结构,那么部署代码生成器或宏魔术来帮助您维护事物可能是值得的。
另一方面,提供通用校验和的最可靠方法是执行特定于实现的扩展,使您能够避免包含任何填充的结构(您的 (1))。请注意,这会将您绑定(bind)到特定的 C 实现或兼容地实现此类扩展的实现,它可能在某些系统上根本不起作用(例如未对齐访问是硬错误的系统),并且它可能会降低性能其他系统。
您的 (4) 是避免填充的另一种方法,但这将是可移植性和维护的噩梦。尽管如此,它可以提供通用校验和,因为校验和算法不需要关注个别成员。但还要注意,这也对类似于 (3) 的初始化行为提出了要求。这会更便宜,但不会完全自动。
实际上,C 实现不会随意修改填充字节,但它们也不一定会特意保留它们。特别是,即使您根据您的 (3) 严格地进行了零填充,也不能保证通过整个结构赋值或当您按值传递或返回结构时复制填充。如果你想做任何这些事情,那么你需要在接收方采取措施以确保填零,并且需要每个成员的关注。
关于c - 计算结构校验和时跳过/避免对齐填充字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56873659/