2012-09-02 168 views
4

我有創造這樣描述的消息的校驗和操作的指令:校驗和計算 - 所有字節的2的補碼相加

校驗由等於所有字節的二的補碼和一個字節的從開始「消息類型「字,直到消息塊的末尾(不包括傳輸的校驗和)。從最重要的位進行忽略。

我發現的另一個描述是: 校驗和值包含數據消息中其他字(即消息類型,消息長度和數據字)的模256總和的二進制補碼。接收設備可以計算接收到的字的模256總和並將該和加到接收到的校驗和字上。零的結果通常表示消息被正確接收。

我明白這意味着我總結消息中的所有字節的值(不包括校驗和),得到這個數的模256。得到這個數字的二進制補碼,這是我的校驗和。

但我遇到了一個示例消息示例(來自設計文檔,所以我必須假定它已被正確編碼)的問題。

unsigned char arr[] = {0x80,0x15,0x1,0x8,0x30,0x33,0x31,0x35,0x31,0x30,0x33,0x30,0x2,0x8,0x30,0x33,0x35,0x31,0x2d,0x33,0x32,0x31,0x30,0xe}; 

所以最後一個字節0xE是校驗和。我的代碼計算校驗如下:

bool isMsgValid(unsigned char arr[], int len) { 
    int sum = 0; 
    for(int i = 0; i < (len-1); ++i) { 
     sum += arr[i]; 
    } 
    //modulo 256 sum 
    sum %= 256; 

    char ch = sum; 

    //twos complement 
    unsigned char twoscompl = ~ch + 1; 

    return arr[len-1] == twoscompl; 
} 


int main(int argc, char* argv[]) 
{ 
    unsigned char arr[] = {0x80,0x15,0x1,0x8,0x30,0x33,0x31,0x35,0x31,0x30,0x33,0x30,0x2,0x8,0x30,0x33,0x35,0x31,0x2d,0x33,0x32,0x31,0x30,0xe}; 
    int arrsize = sizeof(arr)/sizeof(arr[0]); 

    bool ret = isMsgValid(arr, arrsize); 

    return 0; 
} 

該規範是在這裏:= http://www.sinet.bt.com/227v3p5.pdf

我想我誤解了所需要的算法。任何想法如何創建這個校驗和?

Flippin規格作者在他們的數據示例中犯了一個錯誤。剛剛發現這個,然後回到這裏,發現其他人也發現了。對不起,如果我浪費你的時間。我會研究答覆,因爲它看起來像是一些有用的改進我的代碼的評論。

+2

我認爲在數據(0xe)校驗和是不正確的。它似乎只是前面字節的8位總和的補碼。 –

+0

校驗和是正確的。看到我的答案。 –

+1

請注意,如果其中一個值少一個,而另一個值多一個,則校驗和會通過。例如,原始集{1,2,3,4,5},無效集(但通過){1,3,3,3,5}。這種校驗錯誤耗費我4天的調試時間! –

回答

5

您錯過了您鏈接的pdf中的示例消息。第二個參數長度是9個字節,但在代碼中使用了0x08。

當參數中有9個字節時,文檔在第三列中錯誤地指出「8字節」。第二列正確指出「00001001」。

換句話說,你的測試的信息應該是:

{0x80,0x15,0x1,0x8,0x30,0x33,0x31,0x35,0x31,0x30,0x33,0x30, // param1 
0x2,0x9,0x30,0x33,0x35,0x31,0x2d,0x33,0x32,0x31,0x30,0xe} // param2 
    ^^^ 

有了正確的信息陣列,ret == true當我嘗試你的程序。

+1

我一直在看數據和CallerID字符串的大小是錯誤的。如你所說,而不是8。有了這個校正值,校驗和值就可以運行了。非常感謝您的參與。這些數據來自規範。 –

+2

沒問題。你應該聽取其他人關於使用無符號類型的建議。 –

1

同意評論:看起來像校驗和是錯誤的。 .PDF中的數據是這個數據嗎?

一些一般提示:

使用無符號類型作爲累加器;在溢出時給你定義好的行爲,並且你需要更長的消息。同樣,如果將結果存儲在char變量中,則使其成爲unsigned char。

但是你不需要存儲它;只需用無符號類型做數學運算,補充結果,加1,然後屏蔽掉高位,這樣就可以得到8位結果。如果你使用的是使用二進制補碼算法的硬件:只需添加所有值,包括校驗和,然後屏蔽掉高位;然後,如果輸入正確,結果將爲0。

1

接收設備可以計算接收到的字的模256總和並將該和加到接收到的校驗和字上。

它更容易使用這個條件來了解校驗:

{byte 0} + {byte 1} + ... + {last byte} + {checksum} = 0 mod 256 
{checksum} = -({byte 0} + {byte 1} + ... + {last byte}) mod 256 

正如其他人說,你真的應該與各個位工作時使用無符號類型。進行模塊化運算時也是如此。如果您使用簽名類型,則會讓您自己打開一個相當大的數量與簽名相關的錯誤。 OTOH,幾乎是你打開使用無符號數字的唯一錯誤,就像忘記2u-3u是一個正數。

(千萬要小心符號和無符號數混合在一起:有很多涉及太微妙的)