假设我有以下2个基于2个字节的结构:
#pragma pack(1)
struct Foo {
unsigned short a : 5;
unsigned short b : 4;
unsigned short c : 2;
unsigned short d : 5;
} ;
struct Bar {
unsigned short a : 5;
unsigned short b : 4;
unsigned short c : 2;
unsigned short d : 3;
unsigned short e : 2;
} ;
我有一个包含它们的联盟:
union Baz {
unsigned short val;
struct Foo foo;
struct Bar bar;
} ;
然后在我的程序中,我可以使用val来设置一个值,并根据它们的位域获得a,b,c,d和e值,不需要按位操作/接口等。
问题是,我需要它支持大端和小端,这意味着我需要让我的struct根据编译时的字节顺序定义位域。
因此,我需要这样的事情:
#pragma pack(1)
#if BIG_ENDIAN
struct Foo {
unsigned short a : 5;
unsigned short b : 4;
unsigned short c : 2;
unsigned short d : 5;
} ;
struct Bar {
unsigned short a : 5;
unsigned short b : 4;
unsigned short c : 2;
unsigned short d : 3;
unsigned short e : 2;
} ;
#else
struct Foo {
unsigned short d : 5;
unsigned short c : 2;
unsigned short b : 4;
unsigned short a : 5;
} ;
struct Bar {
unsigned short e : 2;
unsigned short d : 3;
unsigned short c : 2;
unsigned short b : 4;
unsigned short a : 5;
} ;
#endif
我尝试了这个,我找到的只是运行时检查或编译后的值,只能在运行时使用。 我知道有许多宏,如BYTE_ORDER,LITTLE_ORDER,BIG_ORDER等,但我不能确保它们将在请求的部署环境中定义,以及endian.h头文件。另外,据我所知,boost的endian.hpp正在实现我上面提到的关于宏的内容,所以我不确定它会有什么不同......
有什么建议吗?
EDIT1: 回答其中一条评论:我需要一个c ++ 03解决方案,但c ++ 11/14也可以用于启蒙。
答案 0 :(得分:1)
问题对于一个简单的简短问题来说太长了:'我如何在编译期间知道endiannes。'并且遗憾的是,这个问题的答案是'你不能' ;
问题是,Posix和C / C ++标准都没有指定关于字节序的任何内容。您唯一能做的就是测试已知的特定于体系结构的宏并从中派生出enddiannes。
答案 1 :(得分:0)
正如我在评论中所说的那样,人们可以用std::bitset
我还不能在大端机器上测试它,因此如果某人有这样的处理并发现了一个错误,我会很感激消息。
#include <iostream>
#include <iomanip>
#include <bitset>
#include <endian.h>
using std::size_t;
struct BE {};
struct LE {};
#if __BYTE_ORDER == __BIG_ENDIAN
using PE = BE;
#else
using PE = LE;
#endif
template<typename> struct BitTraits{};
template<> struct BitTraits<uint8_t> {
constexpr static size_t numbits = 8;
};
template<> struct BitTraits<uint16_t> {
constexpr static size_t numbits = 16;
};
template<typename T>
class BitField {
public:
using assignment_type = T;
using container_type =
typename std::bitset<BitTraits<T>::numbits>;
inline BitField(assignment_type data) : data_(data) {}
inline BitField& operator=(assignment_type data) {
data_ = data;
return *this;
}
inline container_type& data() {
return data_;
}
inline unsigned long long to_ullong() const {
return data_.to_ullong();
}
private:
container_type data_;
};
template<size_t, typename Endianness = PE> struct BitSliceTraits;
template<size_t length>
struct BitSliceTraits<
length,
typename std::enable_if<1<=length && length<=8, PE>::type
> {
using assignment_type = uint8_t;
inline static assignment_type little_endian(assignment_type b) {
return b;
}
};
template<size_t length>
struct BitSliceTraits<
length,
typename std::enable_if<9<=length && length<=16, LE>::type
> {
using assignment_type = uint16_t;
inline static assignment_type little_endian(assignment_type b) {
return b;
}
};
template<size_t length>
struct BitSliceTraits<
length,
typename std::enable_if<9<=length && length<=16, BE>::type
> {
using assignment_type = uint16_t;
inline static assignment_type little_endian(assignment_type b) {
assignment_type rv = (b & 0xFF) >> 8;
rv |= (b & 0xFF00) << 8;
return rv;
}
};
template<class B, size_t start, size_t end>
struct BitSlice {
static constexpr size_t length = end - start + 1;
using assignment_type =
typename BitSliceTraits<length>::assignment_type;
using ref_type = typename B::container_type;
inline explicit BitSlice(B& bf) noexcept : ref(bf.data()) {}
inline BitSlice& operator= (assignment_type arg) noexcept {
arg = BitSliceTraits<length>::little_endian(arg);
for (size_t i = start; i <= end; ++i) {
ref[i] = (arg & (1 << (i - start))) != 0 ? true : false;
}
return *this;
}
inline operator assignment_type () const noexcept {
assignment_type rv(0);
for (size_t i = start; i <= end; ++i) {
rv |= (assignment_type(ref[i]) << (i - start));
}
return rv;
}
ref_type& ref;
};
template<typename B>
struct BitFieldView {
using bitfield_type = B;
};
struct FooView : public BitFieldView<BitField<unsigned short>> {
using bft = bitfield_type;
inline explicit FooView (bft& bf) noexcept : a(bf), b(bf), c(bf) {}
BitSlice<bft, 0, 11> a; // 12
BitSlice<bft, 12, 12> b; // 1
BitSlice<bft, 13, 15> c; // 3
};
struct BarView : public BitFieldView<BitField<unsigned short>> {
using bft = bitfield_type;
inline explicit BarView (bft& bf) noexcept : a(bf), b(bf), c(bf), d(bf) {}
BitSlice<bft, 0, 3> a; //4
BitSlice<bft, 4, 7> b; //4
BitSlice<bft, 8, 11> c; //4
BitSlice<bft, 12, 15> d; //4
};
std::ostream& operator<<(std::ostream& os, uint8_t val) {
return os << std::hex << ulong(val);
}
int main(){
// BIOS FOOD
// 0xB105 0xF00D
{
BitField<unsigned short> bf = 0x0;
// 0xB105 = 1011 0001 0000 0101 = 101 1 000100000101;
FooView(bf).a = 0b000100000101;
FooView(bf).b = 1;
FooView(bf).c = 0b101;
std::cout << std::hex << bf.to_ullong() << ' ';
}
{
// 0xF00D
BitField<unsigned short> bf = 0b1111000000001101;
std::cout << BarView(bf).d
<< BarView(bf).c
<< BarView(bf).b
<< BarView(bf).a
<< std::endl;
}
return EXIT_SUCCESS;
}
live在Coliru的
输出:
b105 f00d