簡體   English   中英

將位數組轉換為字節數組

[英]Convert array of bits to an array of bytes

我想將值為 1 和 0 的位數組 (bool* bitArray) 轉換為字節數組 (unsigned char* byteArray),其中每個索引處的值都是一個字節。 例如,bitArray 中的索引 0~7 將進入 byteArray[1]。

我該怎么做呢? 假設我已經有一個位數組(但數量會根據傳入的數據而變化)。 我不擔心它可以被 8 整除,因為我只需在 bitArray 的末尾添加填充以使其可以被 8 整除。

只需使用位移位或查找數組,然后將數字與 1 位組合,每次按位或 8 位設置:

int main() {
    bool input[] = {
        false, false, false, true, true, true, false, false, false,
        false, false, false, true, true, true, false, false, false,
        false, false, false, true, true, true, false, false, false,
        false, false, false, true, true, true, false, false, false,
    };

    constexpr auto len = sizeof(input) / sizeof(*input);
    constexpr size_t outLen = ((len % 8 == 0) ? 0 : 1) + len / 8;

    uint8_t out[outLen];

    bool* inPos = input;
    uint8_t* outPos = out;

    size_t remaining = len;

    // output bytes where there are all 8 bits available
    for (; remaining >= 8; remaining -= 8, ++outPos)
    {
        uint8_t value = 0;
        for (size_t i = 0; i != 8; ++i, ++inPos)
        {
            if (*inPos)
            {
                value |= (1 << (7 - i));
            }
        }
        *outPos = value;
    }

    if (remaining != 0)
    {
        // output byte that requires padding
        uint8_t value = 0;
        for (size_t i = 0; i != remaining; ++i, ++inPos)
        {
            if (*inPos)
            {
                value |= (1 << (7 - i));
            }
        }
        *outPos = value;
    }

    for (auto v : out)
    {
        std::cout << static_cast<int>(v) << '\n';
    }

    return 0;
}

|=運算符的 rhs 也可以替換為以下數組中的查找,如果您認為這更容易理解:

constexpr uint8_t Bits[8]
{
    0b1000'0000,
    0b0100'0000,
    0b0010'0000,
    0b0001'0000,
    0b0000'1000,
    0b0000'0100,
    0b0000'0010,
    0b0000'0001,
};

...
value |= Bits[i];
...

您應該將std::bitset用於布爾數組,或者std::vector<bool>如果它是動態大小的。 std::array用於數組或std::vector用於動態大小。 我只做了下面的靜態尺寸和相互轉換。

對於應該是 memcpy 的東西(在 little endian 或 unsigned char 類型上),轉換涉及大量位移和循環。 -O2 的編譯器輸出不好。 -O3 刪除循環並且 to_array2 變得有趣。 gcc 幾乎設法對其進行了優化,clang 實際上將其歸結為movzx eax, word ptr [rdi]https ://godbolt.org/z/4chb8o81e

#include <array>
#include <bitset>
#include <climits>

template <typename T, std::size_t len>
constexpr std::bitset<sizeof(T) * CHAR_BIT * len> from_array(const std::array<T, len> &arr) {
    std::bitset<sizeof(T) * CHAR_BIT * len> res;
    std::size_t pos = 0;
    for (auto x : arr) {
        for(std::size_t i = 0; i < sizeof(T) * CHAR_BIT; ++i) {
            res[pos++] = x & 1;
            x >>= 1;
        }
    }
    return res;
}

template <typename T, std::size_t len>
constexpr std::array<T, (len + sizeof(T) * CHAR_BIT - 1) / (sizeof(T) * CHAR_BIT)> to_array(const std::bitset<len> &bit) {
    std::array<T, (len + sizeof(T) * CHAR_BIT - 1) / (sizeof(T) * CHAR_BIT)> res;
    T mask = 1;
    T t = 0;
    std::size_t pos = 0;
    for (std::size_t i = 0; i < len; ++i) {
        if (bit[i]) t |= mask;
        mask <<= 1;
        if (mask == 0) {
            mask = 1;
            res[pos++] = t;
            t = 0;
        }
    }
    if constexpr (len % (sizeof(T) * CHAR_BIT) != 0) {
        res[pos] = t;
    }
    return res;
}

std::bitset<16> from_array2(const std::array<unsigned char, 2> &arr) {
    return from_array(arr);
}

std::array<unsigned short, 1> to_array2(const std::bitset<16> &bits) {
    return to_array<unsigned short>(bits);
}

#include <iostream>

int main() {
    std::array<unsigned char, 2> arr{0, 255};
    std::bitset bits = from_array(arr);
    std::cout << bits << std::endl;

    std::bitset<16> bits2{0x1234};
    std::array<unsigned short, 1> arr2 = to_array<unsigned short>(bits2);
    std::cout << std::hex << arr2[0] << std::endl;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM