CRC我就拿下了

news/2024/11/15 23:28:09/文章来源:https://www.cnblogs.com/xgj-0817/p/18298223

国人讲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 datadata = 0x35B;           // 1101011011b
// append W zeros to the datadata <<= CRC_WIDTH;
// initial the regsregs = 0;
// processingfor(shift_bit=DATA_WIDTH+CRC_WIDTH; shift_bit>0; shift_bit--){// shiftregs = (regs<<1) | ((data>>(shift_bit-1))&0x1);// xorif(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 01 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 01 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 01 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  : 16
Poly   : 1021
Init   : FFFF
RefIn  : False
RefOut : False
XorOut : 0000
Check  : ?

Name   : "XMODEM"
Width  : 16
Poly   : 8408
Init   : 0000
RefIn  : True
RefOut : True
XorOut : 0000
Check  : ?

Name   : "ARC"
Width  : 16
Poly   : 8005
Init   : 0000
RefIn  : True
RefOut : True
XorOut : 0000
Check  : ?
复制代码

 

好,至此就介绍完了,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 datadata <<= CRC_WIDTH;
// print for debugprintf("data -->\t0x%lx\t", data);for(i=DATA_WIDTH+CRC_WIDTH-1; i>=0; i--){printf("%d ", (data>>i)&0x1);}printf("\n");
// processingfor(shift_bit=DATA_WIDTH+CRC_WIDTH; shift_bit>0; shift_bit--){// shift of 1 cycleregs = (regs<<1) | ((data>>(shift_bit-1))&0x1);// xor of 1 cycleif(regs>>CRC_WIDTH)     regs = regs ^ CRC_POLY;// resultprint_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
#endifvoid 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 generationfor(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  CRC32table[index] = (unsigned int)temp;
#elsetable[index] = (unsigned short)temp;
#endif}
// crc calculationpointer = 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  CRC32printf("result --> 0x%Xh\n", regs);
#elseprintf("result --> 0x%Xh\n", (unsigned short)regs);
#endifreturn 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
#endifvoid 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 generationfor(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  CRC32table[index] = (unsigned int)temp;
#elsetable[index] = (unsigned short)temp;
#endif}
// crc calculationpointer = 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  CRC32printf("result --> 0x%Xh\n", regs);
#elseprintf("result --> 0x%Xh\n", (unsigned short)regs);
#endifreturn 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");
}
复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/742471.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在vscode中打开浏览器

在html页面右键,选择 open in default browser 即可打开默认浏览器 布局——<!-- 文档类型为html --> <!DOCTYPE html> <html lang="en"> <head><!-- 字符集为utf-8 --><meta charset="UTF-8"><!-- 设置浏览器兼容…

[Java]“不同族”基本数据类型间只能“强转”吗?

本篇文章标题即摘要,就不赘述。 如果文中有不妥或不对的,多多交流。【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18298193 出自【进步*于辰的博客】本文阐述需要计算不同位二进制的表示范围,引用博文《[MySQ…

还在困惑需要多少数据吗?来看看这份估计指南 | CVPR 2022

论文基于实验验证,为数据需求预测这一问题提供了比较有用的建议,详情可以直接看看Conclusion部分。 来源:晓飞的算法工程笔记 公众号论文: How Much More Data Do I Need? Estimating Requirements for Downstream Tasks论文地址:https://arxiv.org/abs/2207.01725 论文代…

uniapp实现问卷多项填空

产品提出了一个需求,需要实现类似问卷星的记录单,要求有单选,多选,填空,以及多项填空。前三者好实现,最后一个花费了我挺长的时间。 在pc端后台管理模板选项设置的时候,保存是将整个问题保存进去,以三个或三个以上的下划线为一个空,保存的形式例为: cm* cm*___ cm…

编译器

本页面主要介绍了各系统下各类编译器/解释器的安装步骤。 GCC Windows 手动下载安装 访问 MinGW-w64 的下载页面,有多个构建版本。方便起见,我们使用由 WinLibs 提供的构建版本。 首先前往 WinLibs 下载最新的安装包,选择合适的版本,本文选择了 GCC 12.3.0 + LLVM/Clang/LL…

MacOS 15 Sequoia 启用允许“任何来源”应用

MacOS 15 Sequoia 新系统中,spctl --master-disabl指令被禁用,无法启用允许“任何来源”应用程序,导致每一次安装新的应用程序,需要手动在设置中允许,十分麻烦。MacOS 15 Sequoia 启用允许“任何来源”应用 spctl 无法使用 在 MacOS 15 Sequoia Beta3 系统中 spctl 命令被…

ctfshow sql-labs(笔记)

这是当时做题的时候记得笔记有些乱看不懂的可以私我 判断闭合方式: id=1’ and 1=1–+ *正常回显* id=1’ and 1=2–+ *异常回显*id=1 and 1=1 *正常回显* id=1 and 1=2 *异常回显*id=1’) and 1=1–+ 回显正常 id=1’) and 1=2–+ 回显异常id=1") and 1=1–+ 正常回显 id…

服务器(RAID1)数据丢失恢复

服务器数据恢复是指将物理服务器或虚拟服务器上丢失的数据重现还原的操作。配备服务器方便数据集中存储管理,建立信息系统。服务器上的数据通常是存储在硬盘上,出于数据安全和性能的考虑,这些硬盘会组建RAID1磁盘阵列。服务器中的数据丢失了会带来巨大损失,所以,定期对服务…

服务器异常状态怎么解决

服务器异常状态的解决方法需要根据具体的问题和故障类型来确定。 一、硬件故障 检查电源和连接: 确保电源线没有松动或损坏。 检查电源插座是否有电。 如果服务器有多个电源单元,确保它们都在正常工作。 检查内部硬件: 检查服务器的内存条是否完全插入插槽中,并且与服务器兼…

服务器(RAID)数据丢失了如何恢复?

一、评估数据丢失情况 确认数据丢失的原因:了解数据丢失的具体原因,如硬件故障、软件问题、人为错误、病毒攻击等,有助于确定合适的恢复策略。 检查RAID状态:查看RAID控制器的状态报告,了解是否有硬盘故障、RAID级别变化或其他异常情况。 二、尝试初步恢复措施 检查备份:…

【日记】京爷居然带她孩子来这个小县城学舞……(656 字)

正文今天暴晒。太阳好得就像昨天的暴雨是假的一样。昨晚睡得晚,今早困得不行。不过还是在 11:30 的时候,趁着空隙出去把信件寄了出去。感冒还是没好的样子,还是有鼻炎,还鼻塞。鼻子里面总热热的,呼出热气,感觉不太舒服。珍的工作环境好像变得恶劣了一些,祝她好运吧。有点…

什么原因会导致raid掉阵

RAID掉阵,即RAID磁盘阵列失效或无法正常工作,可能由多种原因引起。 一、硬件故障 硬盘故障: 阵列中的硬盘出现物理故障,如电路板损坏、磁头损坏、盘面损坏、坏扇区等,会导致RAID无法正常工作。这些故障可能是由于硬盘老化、使用环境恶劣(如温度过高、湿度过大)、意外碰撞…