VC++实现汉明码
海明碼一般指漢明碼;
漢明碼(Hamming Code)。漢明碼在傳輸的消息流中插入驗證碼,當計算機存儲或移動數據時,可能會產生數據位錯誤,以偵測并更正單一比特錯誤。由于漢明編碼簡單,它們被廣泛應用于內存(RAM)。
與其他的錯誤校驗碼類似,漢明碼也利用了奇偶校驗位的概念,通過在數據位后面增加一些比特,可以驗證數據的有效性。利用一個以上的校驗位,漢明碼不僅可以驗證數據是否有效,還能在數據出錯的情況下指明錯誤位置。
以數據碼1101為例說明漢明碼編碼原理,此時D4=1、D3=1、D2=0、D1=1;
Pn為校驗位;
在P1編碼時,先將D4、D3、D1的二進制碼相加,結果為奇數3,漢明碼對奇數結果編碼為1,偶數結果為0(奇數位。若奇數結果編碼為0.偶數結果為1,則叫偶數位),因此P1值為1,D4+D2+D1=2,為偶數,那么P2值為0,D3+D2+D1=2,為偶數,P3值為0。這樣,漢明碼處理的結果就是1101001。
先看控制臺版本的運行情況;
VC++版的運行情況;單文檔工程;
?代碼都在視類CPP文件中;
// hmmView.cpp : implementation of the CHmmView class //#include "stdafx.h" #include "hmm.h"#include "hmmDoc.h" #include "hmmView.h"#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endifvoid encode(unsigned char data[4], unsigned char code[5]); void code_to_bitarray(unsigned char code[5], unsigned char p[39]); void bitarray_to_wng(unsigned char p[39], unsigned char wng[6]); unsigned char locate_bit(unsigned char wng[6]); void bitarray_to_code(unsigned char p[39], unsigned char code[5]); void bitarray_to_data(unsigned char p[39], unsigned char data[4]); bool decode(unsigned char code[5], unsigned char data[4]); void filename_to_code(char filename[32], char filename_code[40]); void code_to_filename(char filename_code[40], char filename[32]);/ // CHmmViewIMPLEMENT_DYNCREATE(CHmmView, CView)BEGIN_MESSAGE_MAP(CHmmView, CView)//{{AFX_MSG_MAP(CHmmView)// NOTE - the ClassWizard will add and remove mapping macros here.// DO NOT EDIT what you see in these blocks of generated code!//}}AFX_MSG_MAP// Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP()/ // CHmmView construction/destructionCHmmView::CHmmView() {// TODO: add construction code here}CHmmView::~CHmmView() { }BOOL CHmmView::PreCreateWindow(CREATESTRUCT& cs) {// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT csreturn CView::PreCreateWindow(cs); }/ // CHmmView drawingvoid CHmmView::OnDraw(CDC* pDC) {CHmmDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCString str1;char filename[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234";char filename_code[40];char filename_dst[32];filename_to_code(filename, filename_code);code_to_filename(filename_code, filename_dst);pDC->TextOut(50, 50, filename);pDC->TextOut(50, 80, filename_code);pDC->TextOut(50, 110, filename_dst); }/ // CHmmView printingBOOL CHmmView::OnPreparePrinting(CPrintInfo* pInfo) {// default preparationreturn DoPreparePrinting(pInfo); }void CHmmView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {// TODO: add extra initialization before printing }void CHmmView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {// TODO: add cleanup after printing }/ // CHmmView diagnostics#ifdef _DEBUG void CHmmView::AssertValid() const {CView::AssertValid(); }void CHmmView::Dump(CDumpContext& dc) const {CView::Dump(dc); }CHmmDoc* CHmmView::GetDocument() // non-debug version is inline {ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CHmmDoc)));return (CHmmDoc*)m_pDocument; } #endif //_DEBUG/ // CHmmView message handlersvoid encode(unsigned char data[4], unsigned char code[5]) {unsigned int i, j, bit;unsigned char b, c;unsigned char p[39] = {0};memset(code, 0, sizeof(code));for (i = 1; i <= 32; i++) {j = (i-1) / 8;bit = (i-1) % 8;b = (data[j] & (1 << bit));switch (i) {case 1:c = (b << 2) % 0xff;code[0] |= c;break;case 2: case 3: case 4:c = (b << 3) % 0xff;code[0] |= c;break;case 5: case 6: case 7: case 8: case 9: case 10: case 11:c = (b << 4) % 0xff;code[1] |= c;break;case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19:c = (b << 5) % 0xff;code[2] |= c;break;case 20: case 21: case 22: case 23: case 24: case 25: case 26:c = (b << 5) % 0xff;code[3] |= c;break;case 27: case 28: case 29: case 30: case 31: case 32:c = (b << 6) % 0xff;code[4] |= c;break;}}for (i = 1; i <= 38; i++) {if (i != 0x01 && i != 0x02 && i != 0x04 && i != 0x08 && i != 0x10 && i != 0x20) {bit = (i-1) % 8;switch (i) {case 3: case 5: case 6: case 7:p[i] = (code[0] & (1 << bit)) >> bit;break;case 9: case 10: case 11: case 12: case 13: case 14: case 15:p[i] = (code[1] & (1 << bit)) >> bit;break;case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24:p[i] = (code[2] & (1 << bit)) >> bit;break;case 25: case 26: case 27: case 28: case 29: case 30: case 31:p[i] = (code[3] & (1 << bit)) >> bit;break;case 33: case 34: case 35: case 36: case 37: case 38:p[i] = (code[4] & (1 << bit)) >> bit;break;}}}p[1] = p[3] ^ p[5] ^ p[7] ^ p[9] ^ p[11] ^ p[13] ^ p[15] ^ p[17] ^ p[19] ^ p[21] ^ p[23] ^ p[25] ^ p[27] ^ p[29] ^ p[31] ^ p[33] ^ p[35] ^ p[37];p[2] = p[3] ^ p[6] ^ p[7] ^ p[10] ^ p[11] ^ p[14] ^ p[15] ^ p[18] ^ p[19] ^ p[22] ^ p[23] ^ p[26] ^ p[27] ^ p[30] ^ p[31] ^ p[34] ^ p[35] ^ p[38];p[4] = p[5] ^ p[6] ^ p[7] ^ p[12] ^ p[13] ^ p[14] ^ p[15] ^ p[20] ^ p[21] ^ p[22] ^ p[23] ^ p[28] ^ p[29] ^ p[30] ^ p[31] ^ p[36] ^ p[37] ^ p[38];p[8] = p[9] ^ p[10] ^ p[11] ^ p[12] ^ p[13] ^ p[14] ^ p[15] ^ p[24] ^ p[25] ^ p[26] ^ p[27] ^ p[28] ^ p[29] ^ p[30] ^ p[31];p[16] = p[17] ^ p[18] ^ p[19] ^ p[20] ^ p[21] ^ p[22] ^ p[23] ^ p[24] ^ p[25] ^ p[26] ^ p[27] ^ p[28] ^ p[29] ^ p[30] ^ p[31];p[32] = p[33] ^ p[34] ^ p[35] ^ p[36] ^ p[37] ^ p[38];code[0] |= p[1];code[0] |= (p[2] << 1);code[0] |= (p[4] << 3);code[0] |= (p[8] << 7);code[1] |= (p[16] << 7);code[3] |= (p[32] << 7); }void code_to_bitarray(unsigned char code[5], unsigned char p[39]) {unsigned int i, j, bit;for (i = 1; i <= 38; i++) {j = i - 1;bit = j % 8;p[i] = (code[j / 8] & (1 << bit)) >> bit;} }void bitarray_to_wng(unsigned char p[39], unsigned char wng[6]) {wng[0] = p[1] ^ p[3] ^ p[5] ^ p[7] ^ p[9] ^ p[11] ^ p[13] ^ p[15] ^ p[17] ^ p[19] ^ p[21] ^ p[23] ^ p[25] ^ p[27] ^ p[29] ^ p[31] ^ p[33] ^ p[35] ^ p[37];wng[1] = p[2] ^ p[3] ^ p[6] ^ p[7] ^ p[10] ^ p[11] ^ p[14] ^ p[15] ^ p[18] ^ p[19] ^ p[22] ^ p[23] ^ p[26] ^ p[27] ^ p[30] ^ p[31] ^ p[34] ^ p[35] ^ p[38];wng[2] = p[4] ^ p[5] ^ p[6] ^ p[7] ^ p[12] ^ p[13] ^ p[14] ^ p[15] ^ p[20] ^ p[21] ^ p[22] ^ p[23] ^ p[28] ^ p[29] ^ p[30] ^ p[31] ^ p[36] ^ p[37] ^ p[38];wng[3] = p[8] ^ p[9] ^ p[10] ^ p[11] ^ p[12] ^ p[13] ^ p[14] ^ p[15] ^ p[24] ^ p[25] ^ p[26] ^ p[27] ^ p[28] ^ p[29] ^ p[30] ^ p[31];wng[4] = p[16] ^ p[17] ^ p[18] ^ p[19] ^ p[20] ^ p[21] ^ p[22] ^ p[23] ^ p[24] ^ p[25] ^ p[26] ^ p[27] ^ p[28] ^ p[29] ^ p[30] ^ p[31];wng[5] = p[32] ^ p[33] ^ p[34] ^ p[35] ^ p[36] ^ p[37] ^ p[38]; }unsigned char locate_bit(unsigned char wng[6]) {unsigned char loc = 0;char i = 0;for (i = 5; i >= 0; i--) {loc |= (wng[i] << i);}return loc; }void bitarray_to_code(unsigned char p[39], unsigned char code[5]) {unsigned int i, j;unsigned char bit;memset(code, 0, sizeof(code));for(i = 1; i <= 38; i++) {j = i - 1;bit = j % 8;code[j / 8] |= (p[i] << bit);} }void bitarray_to_data(unsigned char p[39], unsigned char data[4]) {memset(data, 0, sizeof(data));unsigned char d[32];unsigned char bit = 0;unsigned int i, j;j = 0;for (i = 1; i <= 38; i++) {if (i != 1 && i != 2 && i != 4 && i != 8 && i != 16 && i != 32) {d[j++] = p[i];}}for (i = 0; i < 32; i++) {bit = i % 8;data[i / 8] |= (d[i] << bit);} }bool decode(unsigned char code[5], unsigned char data[4]) {unsigned char bit;unsigned char p[39] = {0};unsigned char wng[6] = {0};unsigned char loc = 0;code_to_bitarray(code, p);bitarray_to_wng(p, wng);loc = locate_bit(wng);if (0 == loc) {bitarray_to_data(p, data);return true;} else {p[loc] = 1 - p[loc];bitarray_to_code(p, code);bitarray_to_data(p, data);return false;} }void filename_to_code(char filename[32], char filename_code[40]) {int i = 0;for(i = 0; i < 8; i++) {encode((unsigned char*)(filename + i * 4), (unsigned char*)(filename_code + i * 5));} }void code_to_filename(char filename_code[40], char filename[32]) {int i = 0;for (i = 0; i < 8; i++) {decode((unsigned char*)(filename_code + i * 5), (unsigned char*)(filename + i * 4));} }我還不太理解此程序;原程序在?C語言實現海明碼_comeonzz的博客-CSDN博客_c語言海明碼?
漢明碼如果是4位的信息位,校驗位應為3位,編碼后總的碼字為7位;
? ? 原理如上圖;a0-2,校驗位;a3-6為數據位;a2是a6、a5、a4相加得到的;
看不出代碼是如何實現的數據位相加得到?校驗位;
大略理解一下其函數,
encode(unsigned char data[4], unsigned char code[5]) ,實現編碼,輸入是4字節,輸出為5字節;
void code_to_bitarray(unsigned char code[5], unsigned char p[39]) ,字符數組轉為二進制數組;
void bitarray_to_wng(unsigned char p[39], unsigned char wng[6]) ,二進制數組轉為字符數組;
bitarray_to_code(unsigned char p[39], unsigned char code[5]) ,二進制數組轉為編碼后的字符數組;
void bitarray_to_data(unsigned char p[39], unsigned char data[4]) ,二進制數組轉為數據位的字符數組;
bool decode(unsigned char code[5], unsigned char data[4]) ,解碼;
程序是4字節的數據位,編碼后得到的碼字為5字節;
我學過的是4位的數據位,編碼后得到7位碼字,這是電信方面用的;4字節數據編碼后的碼字為5字節,這可能是計算機方面用的;
從它的編碼函數來看;p[0]到p[38]中,p[1]、p[2]、p[4]、p[8]、p[16]、p[32]是校驗位;校驗位通過不同的數據位異或起來得到;
下回繼續;
總結
- 上一篇: Bochs调试Linux内核6 - 启动
- 下一篇: MFC CString转换为字符数组