2017年5月20日 星期六

C and C++ 如何用簡易的方式提取 特定位元(bit) 又可直接存取整個數據

C and C++ 如何用簡易的方式提取 特定位元(bit) 又可直接存取整個數據

這裡用了幾個技巧來達成這個功能
  • Union
  • struct 位元切割
  • 位元運算

Union

用一句話形容
可以自由的切換檢視角度
這是我自己創的詞可能不是很正確,不過可以很容易的理解
在記憶體內全部都是0和1,並不會區別什麼是 int 什麼是 char 那只不過是經過編譯器的解析,或的正確的數值。
檢視角度指的是對記憶體資料的型態解析,比如說以下的例子
int i=65;
void* p=&i;
現在 P 指向某個記憶體位置,但是不知道他是什麼型態
現在詳細指明他是什麼型態 (先不管成功與否的安全問題)
char* str = (char*)p;
現在你告訴編譯器,當我找str地址的使用char的型態來檢視
cout << str << endl;
現在你可以正確的顯示 ‘A’
這個過程需要指名轉型,使用Union可以共用記憶體
共用之後需要什麼型態就直接用什麼型態
自由的切換檢視角度
union S{
    int i;
    char c;
};
現在我們讓 int 與 char 共用一塊記憶體
    S a;
    a.i = 65;
    cout << "a.c = " << a.c << endl;
結果顯示為 A,可以省去繁瑣的轉型,需要什麼在補上什麼


Struct 位元切割

Struct與Union配合可以任意的取出任意位元
using uch = unsigned char;
union Bit{
    struct Bit_dev{
        uch data: 4;
        uch: 2;
        uch data2: 2;
    } bit;
    uch raw;
};
};
這裡特別的寫法可以獲取特定的位元,不要的部分可以不用設變數
養成好習慣記得把struct的大小分配補滿,比較不會產生誤會
如果你只要取中間的話

using uch = unsigned char;
union Bit{
    struct Bit_dev{
        uch:3;
        uch data:4;
        uch:1; // 可以省略不過補上比較好
    } bit;
    uch raw;
};
用法如下
/*****************************************************************
Name :
Date : 2017/05/07
By   : CharlotteHonG
Final: 2017/05/07
*****************************************************************/
#include <iostream>
#include <bitset>

using uch = unsigned char;
union Bit{
    struct Bit_dev{
        uch data: 4;
        uch: 2;
        uch data2: 2;
    } bit;
    uch raw;
};

int main(int argc, char const *argv[]) {
    S a;
    a.i = 65;
    cout << "a.c = " << a.c << endl;

    Bit b;
    b.raw = 0xF7;
    cout << "b.bit.data=" << (bitset<8>)b.raw << endl;
    cout << "b.bit.data=" << (int)b.bit.data << endl;
    cout << "b.bit.data=" << (int)b.bit.data2 << endl;

    return 0;
}
結果
a.c = A
b.bit.data=11110111
b.bit.data=7
b.bit.data=3
需要注意的部分是順序從左開始還是從右開始,自己看一下很容易可以看出


位元運算

這個比較沒有難度,不過可能不好理解,邏輯運算 &
unsigned char bit = 0xCF;
cout << "bit=" << (bitset<8>)bit << endl;
會印出 11001111 目標是取出中間4個 0011 也就是 3
先右移兩位把不要的推掉
bit >>= 2;
cout << "bit=" << (bitset<8>)bit << endl; // bit=00110011
然後讓右邊4個做 & 運算 (左邊的沒寫到的會被捨去)
bit &= 0xF; // 1111
cout << "bit=" << (bitset<8>)bit << endl; // bit=00000011
如果要取3個的話就不要最左邊的
bit &= 0x7; // 0111

沒有留言:

張貼留言