使用T写入uint8_t

时间:2017-10-03 15:36:19

标签: c++ arrays

我有一个std::uint8_t * bytes成员(ByteArray#bytes),但无法正确添加T值。到目前为止,我只测试了在int = 259索引0,然后我读了它并得到3作为输出。

http://rextester.com/HKU93771

ByteArray.hh

/*
 * Copyright (c) 2017 Uncloud Group. All Rights Reserved.
 *
 * See ~/COPYRIGHT.md.
 */

#ifndef mutils_ByteArray_hh
#define mutils_ByteArray_hh

#include <cstddef>
#include <cstdint>
#include <cstdlib>

// (Endianness is detected at compile time, so...)
// (careful.)

#if __BYTE_ORDER == __LITTLE_ENDIAN
    #define MUTILS_LE
#endif

static std::uint8_t * reversing;
static std::uint8_t i;
static std::uint8_t j;

namespace mutils
{
    // Dynamically-sized array of bytes.

    class ByteArray
    {
    public:
        // (Creates an empty ByteArray.)

        ByteArray() { SetLength(0); }

        ByteArray(std::size_t length)
        {
            bytes = nullptr;
            SetLength(length);
        }

        ~ByteArray()
        {
            std::free(bytes);
        }

        // Read little-endian value.

        template<typename T>
        inline T
        ReadLE(std::size_t index)
        {
            std::uint8_t s = bytes[index];

            #ifdef MUTILS_LE
                return T(s);
            #else
                return reverse<T>(&s);
            #endif
        }

        // Write value using little-endianness.
        // Note: No out-of-bounds check is done.

        template<typename T>
        inline void
        WriteLE(std::size_t index, T value)
        {
            #ifndef MUTILS_LE
                value = reverse(&value);
            #endif
            ((T&) bytes[index]) = value;
        }

        inline auto
        GetLength() { return length; }

        void
        SetLength(std::size_t len);

//      ByteArray
//      SliceView(std::size_t start_v, std::size_t end_v);

    private:
        std::uint8_t * bytes;
        std::size_t length;

        // Reverse the byte-order of a value.

        template<typename T>
        T
        reverse(std::uint8_t * value)
        {
            for (i = 0, j = sizeof(T); (--j) >= sizeof(T); ++i)
                reversing[j] = value[i];

            return T(*reversing);
        }
    };

} // namespace mutils

#endif // mutils_ByteArray_hh

ByteArray.cc

/*
 * Copyright (c) 2017 Uncloud Group. All Rights Reserved.
 *
 * See ~/COPYRIGHT.md.
 */

#include <mutils/ByteArray.hh>
#include <cstddef>
#include <cstdint>
#include <cstdlib>

// Updates the array length.

void
mutils::ByteArray::SetLength(std::size_t len)
{
    if (len == 0) 
         bytes = nullptr;
    else bytes = (std::uint8_t *) realloc(bytes, len);

    length = len;
}

测试

#include <iostream>

int main()
{
    mutils::ByteArray b(4);
    b.WriteLE<int>(0, 259);
    std::cout << b.ReadLE<int>(0) << "\r\n";
    return 0;
}

2 个答案:

答案 0 :(得分:1)

这是memcpy的用途。

T t写入bytes

memcpy(bytes + index, &t, sizeof t);

T

阅读bytes
T result;
memcpy(&result, bytes + index, sizeof result);
return result;

如果字节顺序错误,则在字节数组中反转字节。更改类型T的变量内的字节顺序可能会暂时创建非法表示并触发处理器故障。

其他方法(例如您在WriteLE中使用的指针 - 也会触发处理器故障,例如由于对齐。

只需使用memcpy

(对于严格的别名和按位图像,偶数std::copystd::copy_n有点疑问,第3.9节中的标准使用std::memcpy来达到此目的)

答案 1 :(得分:0)

发布示例,以确定如何在撤消原始类型(如unsignedfloatdouble的字节顺序方面没有问题,而不是结构和等等。

以下输入只会转储写在各个大小端点上的34.5555555559值(在ECMAScript中表示为double AFAIK)的字节。

(注意:float64在ES6中表示为double。)

{
    const arr = new DataView(new ArrayBuffer(16));

    const byte = x =>
    {
        x = x.toString(16).toUpperCase();
        return '#' + ((x.length - 1) ? x : `0${x}`);
    };

    const dump = size =>
    {
        const _arr = [];
        for (let i = 0; i < size; ++i)
            _arr.push(byte( arr.getUint8(i) ));
        return _arr.join(' ');
    };

    arr.setFloat64(0, 34.5555555559, false);
    console.log(`Big-endian: ${ dump(8) }`);

    arr.setFloat64(0, 34.5555555559, true);
    console.log(`Little-endian: ${ dump(8) }`);
}

输出:

  

Big-endian:#40#41#47#1C#71#C7#D9 #CE
  Little-endian:#CE#D9#C7#71#1C#47#41#40

所以你可以注意到字节只在little-endian中被反转。这些位没有区别。在我的代码中,只有当编译器目标是基于big-endian时才需要反转字节。我认为这就是float字节序的工作方式。