国人讲CRC的没有什么能讲明白的文章,除了一篇《我学习 CRC32、CRC16、CRC 原理和算法的总结(与 WINRAR 结果一致)》,这里先感谢他,另,他也有一些没有说明白的地方,怎么说呢,还是鄙人自己来吧。

我弄明白CRC这个原理和算法主要参考的是上面的国人的那篇和这个外国的《A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS INDEX V3.00 (9/24/96)》,地址 http://www.repairfaq.org/filipg/LINK/F_crc_v3.html 这两篇大作。

首先要明确的是CRC只是一种错误检错的码,而没有纠正的作用,那么纠错码可以通过对原数据的+/-/*/÷等进行,但是+/-的问题太大,比如都 是对原数据每个bit进行累加运算,如果出错了的话,比如有1bit的1变为0,1bit的0变为1,+/-运算完全识别不出这种错误,显然这种错误除法 的辨认概率是非常大的,于是不知道哪位大神就把CRC这种校验方式给搞出来了。

这里我先介绍一下CRC的运算方式,其实就是一个数去除以生成多项式,余数就是CRC校验码,但是这里的除法和现实意义上面的除法有点出入。

首先先看一下原始的除法取余运算。正常除法,120÷9=13…3,这里的余数即是我们所要的校验位的码字。

               1 1 0 1        ______________ 1 0 0 1/ 1 1 1 1 0 0 0          被除数120是1111000,除数9是1001          1 0 0 1         -------------            1 1 0 0              第一次减法后得到011           1 0 0 1           -------------                1 1 0 0          第二次减法后得到0101               1 0 0 1           -------------                    1 1   ->     余数是3

这里用的是真正的减法,不好用,要用减法真的,于是将所有减法运算都用XOR运算替换掉,CRC就横空出世了,这里还用120这个数举例子,CRC所用的除法里,120÷9=14…6

               1 1 1 0        ______________ 1 0 0 1/ 1 1 1 1 0 0 0          被除数120是1111000,除数9是1001          1 0 0 1         -------------            1 1 0 0              第一次XOR后得到011           1 0 0 1           -------------              1 0 1 0            第二次XOR后得到0101             1 0 0 1           -------------                  1 1 0   ->     余数是6

这里的6就是真正的CRC校验码,那么他是谁的CRC呢?注意,他不是120的CRC校验码,而是15(0x0F)的CRC校验码,这里为啥是这样,只能说是规定,因为CRC相当于是余数,如果说110b是1111b的CRC校验码,那么将1111 110b排成一排送入CRC模块,剩余的余数就应该是0,规定就是这样的。所以对于110b只能说他是1111b的CRC校验码,不能说他是1111000b的CRC校验码。

通过这个例子,可以说明CRC这种算法的结构,对1111b进行CRC校验运算,校验码是110b,其中,1111b为数据,1001b(9)就是生成多项式,这里的CRC位数为3,记为W=3,因为是在1111b后面追加3bit的数据,所以是CRC3,生成多项式可以写作g(x) = x3+1。以此为例来循序渐进的介绍CRC的3种计算方法。

一、直接计算法

直接计算法就是用寄存器去模拟上面的CRC除法过程,我们假设待测数据是11 0101 1011,生成项是10011(g(x) = x4+x+1),需要有一个4bit的寄存器(因为每次的最高位都必定被XOR为0或者是移位直到最高位为0再XOR),通过反复的移位和进行CRC的除法,最终该寄存器中的值就是我们所要求的余数。开始

1) 待测数据后扩展W=4个比特0,变成1101011011 0000(augmented message);
2) 寄存器初始化置0;
3) 先在寄存器中移入数据1101;
4) 寄存器左移一位,并且右边移入下一位数据0。这样最高位1移出,由于最高位是1,故本次的商是1,要用除数1001来进行XOR,最高位肯定XOR得0,故不管它,只要用低4位0011来进行XOR就可以,即0011对此时寄存器进行XOR,寄存器中得到1001,即第一次 XOR 后的结果(相当于是数据11010与生成项10011进行了一次XOR,并把最高位0消掉了)。 如果移出的最高位是0,则用0000来进行XOR(相当于只是进行了移位)。
5) 一直重复这个过程,就能得到最后余数了。

            3   2   1   0   Bits          +---+---+---+---+ Pop! <-- |   |   |   |   | <----- Augmented message(1101011011 0000)          +---+---+---+---+

代码描述如下

#define CRC_WIDTH   4
#define CRC_POLY    0x3     // 0011b// load data data = 0x35B; // 1101011011b // append W zeros to the data data <<= CRC_WIDTH; // initial the regs regs = 0; // processing for(shift_bit=DATA_WIDTH+CRC_WIDTH; shift_bit>0; shift_bit--){ // shift regs = (regs<<1) | ((data>>(shift_bit-1))&0x1); // xor if(regs>>CRC_WIDTH) regs = regs ^ CRC_POLY; }

这种方法是最直观的方法,先理解了这种方法才能理解后面的方法,从这里的C代码到硬件实现就更简单了,画出电路图

        +---+   +---+   +---+         +---+    +<--|   |<--|   |<--|   |<--XOR<--|   |<--XOR<-- Augmented message    |   +---+   +---+   +---+    ^    +---+    ^    |                            |             |    |                            |             |    +----------------------------+-------------+

稍微体会一下就会明白,看清XOR的位置,对应除法的时候异或运算的处理,就好。

二、驱动表法(table drive)

故名思议,驱动表法就是查表,预先生成一个表,就省得每次都进行XOR费时费力,驱动表法的概念推导却是全靠了直接计算法得来的。(但是其实驱动表法并不是我们常用的查表法,常用的查表法这里被称为“直接查表法”,这是后话。)具体怎么来的呢,听我慢慢道来

首先,举个例子,待测数据是1011 0100b,生成多项式比如是1 0001 1100b,那么我们比如想做的是4bit的查找表,这里查找表的大小其实是无关紧要的,只不过一般都用的是8bit的查找表,因为一般的数据都是以byte为单位的,如果是4bit的查找表那么我们的表大小就是16,但是每个表单元还是根据CRC的宽度定的,话不多说,先来看看直接法计算的过程,

                                   1 0 1 1 1 0 0 0                   ________________________________1 0 0 0 1 1 1 0 0/ 1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0                   1 0 0 0 1 1 1 0 0                   -------------------------------                       1 1 1 0 1 0 0 0 0                       1 0 0 0 1 1 1 0 0                   -------------------------------                         1 1 0 0 1 1 0 0 0                         1 0 0 0 1 1 1 0 0                   -------------------------------                           1 0 0 0 0 1 0 0 0                           1 0 0 0 1 1 1 0 0                   -------------------------------                                   1 0 1 0 0 0 0 0

首先,要知道的是A^B^C = A^(B^C),那么我们在使用直接计算法的时候,针对前4bit,我们需要计算4次,3次都是要计算与生成多项式的XOR结果,那么查表法应运而生,看下面的式子

                                   1 0 1 1 1 0 0 0 ________________________________ 1 0 0 0 1 1 1 0 0/ 1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 ---> 0 0 0 0 0 0 0 0 0 ---> 1 0 0 0 1 1 1 0 0 ---> 1 0 0 0 1 1 1 0 0 ---> ------------------------------- 1 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 0 ------------------------------- 1 0 1 0 0 0 0 0

我们用空间去换时间,计算4次,并且知道要计算的高4bit是1011,那么我们把根据生成多项式进行移位,得出的高4bit为index的table中查出后面的8bit就可以相当于原来的4次高4bit的XOR运算,就可以变成这样

                                   1 0 1 1 1 0 0 0 ________________________________ 1 0 0 0 1 1 1 0 0/ 1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 (1 0 1 1)1 1 0 0 0 1 0 0 ------------------------------- 1 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 0 ------------------------------- 1 0 1 0 0 0 0 0

即是说,应用POLY(生成多项式)来搞出4bit的查找表,index是由生成多项式的最高bit进行移位和XOR运算得到,内容当然也就是上面这样的XOR的后面8bit的结果,针对上面的例子,查找表的生成函数是这样的

#define LUT_WIDTH   4
#define CRC_WIDTH   8
#define CRC_POLY    0x11Cfor(index=0; index<(1<<LUT_WIDTH); index++){ temp = 0; for(bit_cnt=LUT_WIDTH; bit_cnt>0; bit_cnt--){ if((index>>(bit_cnt-1) ^ temp>>(CRC_WIDTH-1))&0x1) temp = (temp<<1) ^ CRC_POLY; else temp <<= 1; } table[index] = (unsigned char)temp; }

这样,表就制作完成了,好进入正题,接着就开始驱动表法的计算方法了,拿到表之后要怎么查呢?(4bit的没人用,为了描述方便,以常用的8bit index的查找表为例叙述)

1)register左移一个字节,从原始数据中读入一个新的字节.  
2)利用刚从register移出的字节作为index定位table中的一个值  
3)把这个值XOR到register中。
4)如果还有未处理的数据则回到第一步继续执行。

              1    0   Bytes+----+----++-----<|    |    | <----- Augmented message|      +----+----+|           ^|           ||          XOR|           ||     0+----+----+ v +----+----+ | +----+----+ | +----+----+ | +----+----+ | +----+----+ | +----+----+ +----->+----+----+ +----+----+ +----+----+ +----+----+ +----+----+ 255+----+----+

这里举个计算的例子,计算0x31, 0x32, 0x33, 0x34对CRC-CCITT(CRC16,POLY=0x1021)的计算。高亮的字体就是每一步的寄存器中的数据。

        __________________  10 21/ 31 32 33 34 00 00            26 72           --> index=31        ------------------            14 41 34 00 00               52 B5        --> index=14        ------------------               13 81 00 00                  22 52     --> index=13        ------------------                  A3 52 00                     85 89  --> index=A3        ------------------                     D7 89

计算过程代码描述

unsigned char   buff[] = {0x31, 0x32, 0x33, 0x34}; unsigned int len = sizeof(buff); unsigned char *pointer; unsigned int regs; pointer = buff; regs = 0; while(len--){ regs = ((regs<<8)|*pointer++) ^ table[(regs>>8)&0xFF]; } // append zeros to finish the calculation for(i=0; i<2; i++){ regs = (regs<<8) ^ table[(regs>>8)&0xFF]; }

三、直驱表法(direct table)

这才是平常软硬件正常使用的方法,先来看看他的庐山真面目(对比图,CRC32),先看下CRC32的驱动表法的图形

              3    2    1    0   Bytes           +----+----+----+----+    +-----<|    |    |    |    | <----- Augmented message    |      +----+----+----+----+    |                ^    |                |    |               XOR    |                |    |     0+----+----+----+----+    v      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    +----->+----+----+----+----+           +----+----+----+----+           +----+----+----+----+           +----+----+----+----+           +----+----+----+----+        255+----+----+----+----+

首先要明确的就是,驱动表法,寄存器的初始值必须是0,之后开始运算,如果不是0的话相当于是在原数据的最高位前面insert了数据,之后,就是后面加上去的0,其实没有真正的作用观察前面{31 32 33 34}计算的表就能得出这个结论,0的实际意义就是要为了把前面的数据都送进register里面进行运算。英文原文解释如下(但是我没看懂 后来自己琢磨明白的)

TAIL
    The W/4 augmented zero bytes that appear at the end of the message will be pushed into the register from the right as all the other bytes are, but their values (0) will have no effect whatsoever on the register because 1) XORing with zero does not change the target byte, and 2) the four bytes are never propagated out the left side of the register where their zeroness might have some sort of influence. Thus, the sole function of the W/4 augmented zero bytes is to drive the calculation for another W/4 byte cycles so that the end of the REAL data passes all the way through the register.
HEAD
    If the initial value of the register is zero, the first four iterations of the loop will have the sole effect of shifting in the first four bytes of the message from the right. This is because the first 32 control bits are all zero and so nothing is XORed into the register. Even if the initial value is not zero, the first 4 byte iterations of the algorithm will have the sole effect of shifting the first 4 bytes of the message into the register and then XORing them with some constant value (that is a function of the initial value of the register).

These facts, combined with the XOR property
(A xor B) xor C = A xor (B xor C)

         31 32 33 34 00 00  --> data(1)=31, data(2)=32, data(3)=33, data(4)=34            26 72           --> index(1)=31, 31 = data(1) ^ 00        ------------------            14 41 34 00 00               52 B5        --> index(2)=14, 14 = data(2) ^ table(index(1))[15:8]        ------------------               13 81 00 00                  22 52     --> index(3)=13, 13 = data(3) ^ table(index(2))[15:8] ^ table(index(1))[7:0]        ------------------                  A3 52 00                     85 89  --> index(4)=A3, A3 = data(4) ^ table(index(3))[15:8] ^ table(index(2))[7:0]        ------------------                     D7 89

观察每一步的index,就会发现,如果是CRC-CCITT的计算,其实的话每一步的index和最终结果都可以这么表示

index(n) = data(n)[7:0] ^ table(index(n-1))[15:8] ^ table(index(n-2))[7:0]; result = index(last);

于是再看直驱表法的图形

    +-----<Message (non augmented)    |    v         3    2    1    0   Bytes    |      +----+----+----+----+   XOR----<|    |    |    |    |    |      +----+----+----+----+    |                ^    |                |    |               XOR    |                |    |     0+----+----+----+----+    v      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    |      +----+----+----+----+    +----->+----+----+----+----+           +----+----+----+----+           +----+----+----+----+           +----+----+----+----+           +----+----+----+----+        255+----+----+----+----+

算法描述

1) Shift the register left by one byte(this byte is called top byte), reading in a new message byte.
2) XOR the top byte with the next message byte to yield an index into the table ([0,255]).
3) XOR the table value into the register.
4) Goto 1 if more message to be processed.

代码这样

// direct table crc calculation, CRC16pointer = buff;regs = CRC_INIT;for(i=0; i<len; i++){ regs = (regs<<8) ^ table[(regs>>8)&0xFF ^ *pointer++]; }

这样的话如果使用这种方法,那么最后append zero的0,因为XOR运算,所以XOR0还是原来的数,于是最后两步的0就省掉了(注:这个过程是首先有了驱动表法,根据计算过程推出了直驱表法,再接着由于推出的直驱表法而省略掉了最后面的augmented zeros)。

还举例子为31323334,POLY还是0x1021的例子

31 --> 00 00       31 26 72      ------------------32 -----> 26 72          14 52 B5      ------------------33 --------> 20 B5             13 22 52      ------------------34 -----------> 97 52                A3 85 89      ------------------                   D7 89

下划线的是每一步的index,高亮的是每一步寄存器中留下的值,可以看出,每一步留下的值相当于都是前面的数据计算所得的CRC校验码。而这里的00,是真正意义上的CRC_INIT,就是寄存器的初始值,其实我觉得反映的就是接着前面计算CRC值再继续进行计算,因为寄存器中每次的值相当于都是前面输入数据的CRC值,那么寄存器中有啥都是前面数据留下的真正的CRC值,所以寄存器的初始值就是这个意思,在什么样的基础上继续进行CRC的计算。

四、CRC计算模型

CRC不止这点东西,还有一些其他的东西要处理,比如CRC其实都是有model的,不光是CRC的POLY和INIT

Name   : "CRC-32" Width  : 32 Poly   : 04C11DB7 Init   : FFFFFFFF RefIn  : True RefOut : True XorOut : FFFFFFFF Check  : CBF43926

这里面知道的不解释,

RefIn  指的就是如果这个值是FALSE,表示待测数据的每个字节都不用“颠倒”,即BIT7仍是作为最高位,BIT0作为最低位。 如果这个值是TRUE,表示待测数据的每个字节都要先“颠倒”,即BIT7作为最低位,BIT0作为最高位。

RefOut  是说如果这个值是FALSE,表示计算结束后,寄存器中的值直接进入XOROUT处理即可。 如果这个值是TRUE,表示计算结束后,寄存器中的值要先“颠倒”,再进入XOROUT处理。注意,这是将整个寄存器的值颠倒,由最高bit到最低bit进行颠倒。

XorOut  这个值与经RefOut后的寄存器的值相XOR,得到的值就是最终正式的CRC值!

Check  就是字符串"123456789"(就是16进制的0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39)经过这个CRC运算的结果作为一个标准,来帮助你检查你的算法是否正确的指标。

常用的CRC model还有

Name   : "CRC-16" Width  : 16 Poly   : 8005 Init   : 0000 RefIn  : True RefOut : True XorOut : 0000 Check  : BB3D

Name   : "CRC-16/CCITT"Width  : 16Poly   : 1021Init   : FFFFRefIn  : FalseRefOut : FalseXorOut : 0000Check  : ?

Name   : "XMODEM"Width  : 16Poly   : 8408Init   : 0000RefIn  : TrueRefOut : TrueXorOut : 0000Check  : ?

Name   : "ARC"Width  : 16Poly   : 8005Init   : 0000RefIn  : TrueRefOut : TrueXorOut : 0000Check  : ?

好,至此就介绍完了,C的全程代码后面附上,verilog的代码稍候带来。

注:我编译的机器是64位的,如果是32位的话有的变量类型需要改变

直接计算法

#include <stdio.h>
#define     CRC_POLY    0x00011021
#define     CRC_WIDTH   16
#define     CRC_INIT    0x00000000
#define     DATA_POLY   0x31323334L
#define     DATA_WIDTH  32void print_regs(int, int, int); int main() { unsigned long data = DATA_POLY; unsigned long regs = CRC_INIT; int shift_bit; int i; // append zeros to the data data <<= CRC_WIDTH; // print for debug printf("data -->\t0x%lx\t", data); for(i=DATA_WIDTH+CRC_WIDTH-1; i>=0; i--){ printf("%d ", (data>>i)&0x1); } printf("\n"); // processing for(shift_bit=DATA_WIDTH+CRC_WIDTH; shift_bit>0; shift_bit--){ // shift of 1 cycle regs = (regs<<1) | ((data>>(shift_bit-1))&0x1); // xor of 1 cycle if(regs>>CRC_WIDTH) regs = regs ^ CRC_POLY; // result print_regs(DATA_WIDTH+CRC_WIDTH-shift_bit+1, CRC_WIDTH, regs); } return 0; } void print_regs(int crc_step, int crc_width, int crc_regs) { int i; printf("Step %d\t\t", crc_step); for(i=crc_width; i>0; i--){ printf("%d ", (crc_regs>>(i-1)&0x1)); } printf("\n"); }

驱动表法

#include <stdio.h>
#define     BYTE_L  8
//#define     CRC32   // default CRC16, unless define CRC32
 #ifdef CRC32 #define CRC_WIDTH 32 #define CRC_POLY 0x04C11DB7 #define CRC_INIT 0x00000000 #else #define CRC_WIDTH 16 #define CRC_POLY 0x1021 #define CRC_INIT 0x0000 #endif void print_regs(unsigned int, unsigned int); int main() { unsigned char bit_cnt ; unsigned short index ; unsigned int table[256] ; unsigned int temp ; unsigned char buff[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}; unsigned int len = sizeof(buff); unsigned char *pointer ; unsigned int regs ; unsigned int i ; // crc LUT generation for(index=0; index<256; index++){ temp = 0; for(bit_cnt=BYTE_L; bit_cnt>0; bit_cnt--){ if((index>>(bit_cnt-1) ^ temp>>(CRC_WIDTH-1))&0x1) temp = (temp<<1) ^ CRC_POLY; else temp <<= 1; } #ifdef CRC32 table[index] = (unsigned int)temp; #else table[index] = (unsigned short)temp; #endif } // crc calculation pointer = buff; regs = CRC_INIT; while(len--){ print_regs(CRC_WIDTH, regs); regs = ((regs<<BYTE_L)|*pointer++) ^ table[(regs>>(CRC_WIDTH-BYTE_L))&0xFF]; } for(i=0; i<CRC_WIDTH/BYTE_L; i++){ print_regs(CRC_WIDTH, regs); regs = (regs<<BYTE_L) ^ table[(regs>>(CRC_WIDTH-BYTE_L))&0xFF]; } #ifdef CRC32 printf("result --> 0x%Xh\n", regs); #else printf("result --> 0x%Xh\n", (unsigned short)regs); #endif return 0; } void print_regs(unsigned int crc_width, unsigned int crc_regs) { int i; for(i=crc_width; i>0; i--){ printf("%d ", (crc_regs>>(i-1)&0x1)); } printf("\n"); }

直驱表法

#include <stdio.h>
#define     BYTE_L  8
//#define     CRC32   // default CRC16, unless define CRC32
 #ifdef CRC32 #define CRC_WIDTH 32 #define CRC_POLY 0x04C11DB7 #define CRC_INIT 0xFFFFFFFF #else #define CRC_WIDTH 16 #define CRC_POLY 0x1021 #define CRC_INIT 0x0000 #endif void print_regs(unsigned int, unsigned int); int main() { unsigned char bit_cnt ; unsigned short index ; unsigned int table[256] ; unsigned int temp ; unsigned char buff[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}; unsigned int len = sizeof(buff); unsigned char *pointer ; unsigned int regs ; unsigned int i ; // crc LUT generation for(index=0; index<256; index++){ temp = 0; for(bit_cnt=BYTE_L; bit_cnt>0; bit_cnt--){ if((index>>(bit_cnt-1) ^ temp>>(CRC_WIDTH-1))&0x1) temp = (temp<<1) ^ CRC_POLY; else temp <<= 1; } #ifdef CRC32 table[index] = (unsigned int)temp; #else table[index] = (unsigned short)temp; #endif } // crc calculation pointer = buff; regs = CRC_INIT; for(i=0; i<len; i++){ print_regs(CRC_WIDTH, regs); regs = (regs<<BYTE_L) ^ table[(regs>>(CRC_WIDTH-BYTE_L))&0xFF ^ *pointer++]; } #ifdef CRC32 printf("result --> 0x%Xh\n", regs); #else printf("result --> 0x%Xh\n", (unsigned short)regs); #endif return 0; } void print_regs(unsigned int crc_width, unsigned int crc_regs) { int i; for(i=crc_width; i>0; i--){ printf("%d ", (crc_regs>>(i-1)&0x1)); } printf("\n"); }

转载于:https://www.cnblogs.com/zqlxinyu/p/4680519.html

CRC 转载自poiu_elab用于收藏相关推荐

  1. Hibernate高级映射技术(二)自定义数据类型StringMap (转载用于收藏)

    转载于:http://ajava.org/course/open/14004.html 核心提示:上一篇文章介绍了数据库中用;分隔的字段的一种方便的高级映射自定义数据类型StringList.这次是我 ...

  2. Hibernate高级映射技术(一)自定义数据类型StringList (转载用于收藏)

    转载于:http://ajava.org/course/open/14003.html 核心提示:我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免 ...

  3. 基于大数据的银行反欺诈的分析报告 【转载,可用于风控系统架设借鉴】

    转载至 https://www.cnblogs.com/yueyebigdata/p/5893454.html  Growth跃爷Hacker (怕收藏至浏览器文件夹有天会有遗漏,转至自己博客中,推荐 ...

  4. [转载]学习整理英文单词收藏

    lay the roots for 为-打下基础 lead  to 导致 lead  into 使-陷入,领-进入 lead-to- 将-引向- leakage 泄露(动词leak) leap  飞跃 ...

  5. 努力吧,现在也不晚(目前唯一一个转载文章,用于激励自己)

    努力吧,现在也不晚 来自http://blog.csdn.net/shuaihj/article/details/8586101 或许这再一次印证任何人每一次的成功背后都有不为人知的付出和汗水.    ...

  6. java学习之路--面试之多线程基础

    Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环 ...

  7. CRC 的简介和应用(转载)

    转自做而论道的百度空间 http://hi.baidu.com/do_sermon/item/6eb87a5425d25baeacc85783 CRC,Cyclic Redundancy Check, ...

  8. ResDepot CRC码

    参考: 百度百科 crc校验 百度百科 crc编码 生日悖论 CRC32能不能用于检验文件的相同性 Egret RES版本控制 一.Egret的ResDepot在发布时,可以添加crc码. 发布前 发 ...

  9. JVM原理及调优--网页链接收藏

    此篇用于收藏大神们关于JVM原理及调优通俗易懂的文章链接,用于随时查看 JVM调优总结 JVM参数配置大全 JVM调优:选择合适的GC collector 菜菜鸟想了解下大概的JVM内存模型可以看这个 ...

最新文章

  1. Flex 布局详解 - 转自阮一峰老师
  2. html表单全选框,form表单里如何实现全选和全不选
  3. 中国非动物胶市场来产销需求及发展潜力研究报告2022版
  4. 使用 SQL Server 2000 索引视图提高性能1
  5. pip指定包的安装路径
  6. suse linux 文件只可读,SUSE LINUX下文件系统变只读的问题解决
  7. 建筑与计算机技术,建筑设计中常用的计算机技术与注意点
  8. SLAM学习策略和前期准备
  9. html5 响应式背景图
  10. 关于用FOMR提交编码的问题
  11. 爬虫(十五):scrapy中的settings详解
  12. 根据IP获取对应国家
  13. Markdown开发VSCode插件推荐
  14. Android 字体自适应屏幕的方法
  15. 如何下载M3U8格式文件,将文件转化为MP3格式进行本地存储。
  16. 猫哥说创业:发布软文赚钱术(1)
  17. NOIP2018提高组 货币系统
  18. dom对象jquery对象
  19. C++ char*类型的实参与 LPCWSTR类型的形参不兼容
  20. 如何清除百度地图api的某个图层

热门文章

  1. SQL经典实例(第一章笔记)
  2. HTML基础讲解笔记
  3. 《商务与经济统计》学习笔记(二)---辛普森悖论
  4. 服务器安培 国内销售渠道,国内药妆销售渠道分析
  5. 基于知识图谱的推荐系统
  6. 如何手动开启STFServer.apk
  7. 2019.12.14
  8. 金融分析师 python_量化金融分析师(AQF)|教你快速学会Python
  9. OpenCv图像处理实战——文档扫描
  10. 节点精灵免Root安卓辅助脚本学习一:搭建环境