我正在尝试计算某些数据的校验和.这是代码:
#include <stdio.h>
#include <string.h>
int main()
{
char MyArray[] = "my secret data";
char checksum = 0;
int SizeOfArray = strlen(MyArray);
for(int x = 0; x < SizeOfArray; x++)
{
checksum += MyArray[x];
}
printf("Sum of the bytes for MyArray is: %d\n", checksum);
printf("The checksum: \n");
checksum = (checksum ^ 0xFF);
printf("%d\n",checksum);
}
Run Code Online (Sandbox Code Playgroud)
输出:
Sum of the bytes for MyArray is: 70
The checksum:
-71
Run Code Online (Sandbox Code Playgroud)
代码中的修改:
#include <stdio.h>
#include <string.h>
int main()
{
char MyArray[] = "my secret data";
char checksum = 0; // could be an int if preferred
int SizeOfArray = strlen(MyArray);
for(int x = 0; x < SizeOfArray; x++)
{
checksum += MyArray[x];
}
printf("Sum of the bytes for MyArray is: %d\n", checksum);
//Perform bitwise inversion
checksum=~checksum;
//Increment
checksum++;
printf("Checksum for MyArray is: %d\n", checksum);
}
Run Code Online (Sandbox Code Playgroud)
输出:
Sum of the bytes for MyArray is: 70
Checksum for MyArray is: -70
Run Code Online (Sandbox Code Playgroud)
为什么修改校验和值?不同的算法会提供不同的校验和吗?
最终价值如何有用?实际上,我不清楚校验和及其在数据验证中的用途.我在网上搜索,发现了很多文章,但仍然不清楚.希望我今天能在这里了解校验和.
在考虑如何生成校验和之前,您需要了解什么是校验和.假设通过不可靠的通信信道(例如网络连接)发送数据的问题.您需要确保没有干扰影响您的消息.
一种方法是将消息发送两次,并检查差异(实际上,在传输两个消息期间发生完全相同的错误的可能性非常小).但是,这需要使用相当多的带宽(发送消息两次).
更有效的方法是根据消息计算值并将其附加到消息中.然后,收件人应用相同的功能并检查值是否相同.
为了获得更直观的示例,书的校验和可以是页数.您从图书馆购买书籍并计算其页数.如果页数不符合您的预期,则会出现问题.
你实现了一个特定的校验和函数(总和的LSB),这很好.所有校验和函数都有一些您应该注意的属性,但重点是没有正确的方法来计算校验和.有许多功能可用于此目的.
这就是校验和算法的美妙之处:生成校验和的方式以及检查它的方式在某种程度上是对称的!
校验和通常用于验证数据的完整性,尤其是在嘈杂/不可靠的通信通道上。因此,它主要用于错误检测。也就是知道接收到的数据是否正确。
这与纠错等方面有很大不同。因为它的用途不仅是检查是否有错误,而且是纠正错误。
错误检测和错误纠正都具有开销(或增强)数据。即,不属于原始数据的一部分,但添加到原始数据中的数据,目的是检查原始数据是否被更改(例如在情况或错误检测中)或纠正它(例如在情况或错误更正)。
与错误检测算法不同,纠错算法的开销数据大小往往与原始数据成比例增长(因为拥有的数据越多,恢复它所需的开销就越大)。
我们通常不希望开销数据太大,因为大数据意味着我们需要处理更多资源(即处理时间、传输时间等)。因此,从这个意义上说,好的校验和算法通常是使用最少量的开销数据来检测错误但具有很强的鲁棒性(极少产生错误结果)的算法。
有了这种理解,问题就出现了,因为校验和的鲁棒性实际上不仅取决于算法,还取决于信道特性。某些通道可能容易出现某些错误,而其他通道可能会出现不同的错误。
然而,一般来说,有一些校验和比其他校验和更受欢迎、更可靠。对于后者,部分原因是它具有固有的属性,可以确保它在大多数(如果不是全部)通道中都具有鲁棒性(我最喜欢的错误检测算法之一是CRC - 循环冗余检查,因为它具有该固有属性)。但并不存在适合每种场景的完美校验和,这实际上取决于用途和场景。
但是,您仍然可以衡量校验和算法的稳健性。有一种数学方法可以做到这一点,我认为这超出了本次讨论的范围。因此,从这些意义上来说,某些校验和可以说比其他校验和弱。您在问题中显示的校验和也是弱校验和,因为它们可能比强校验和(例如 CRC)更容易产生错误结果。
8 位与 0xFF 的异或完全等同于对一个值进行二进制反转,而且不难看出这一点。
与 0xFF 异或
1110 0010
1111 1111
--------- XOR
0001 1101 //notice that this is exactly the same as binary inverting!
Run Code Online (Sandbox Code Playgroud)
因此,当您与 0xFF 和 进行异或时~checksum
,您会得到相同的结果 -71 (并且由于您的数据类型是char
,因此它具有负数)。然后你将它增加 1,这样你就得到 -70。
二进制补码是对二进制数的数学运算,以及基于该运算的二进制有符号数表示。它在计算中的广泛应用使其成为基数补码最重要的例子。(维基百科)
换句话说,2'补码是找到一个值的负表示(在计算机二进制中),其方法是,正如您正确所做的那样,通过反转其所有位,然后向其加一。这就是为什么你得到 -70 by 2' 补 70。但这并不意味着2'补码和 0xFF 的异或是相同的,并且正如您通过示例看到的,它确实不一样。
0xFF 的 XOR 对 8 位数据所做的操作相当于反转其所有位。它不会给它加一。
由于校验和用于了解数据的完整性(无论是否被更改),人们试图找到最佳实践来做到这一点。您所做的实际上是通过 2' 补码或与 0xFF 进行异或来获得校验和。
他们所做的就是这些:
因此,在这两种情况下,您只需检查最终结果是否为 0(无错误)即可检查消息是否包含错误!这对于校验和算法来说通常是正确的!
这就是校验和算法的美妙之处:生成校验和的方式以及检查的方式在某种程度上是对称的!