如何使用位字段以4位为增量访问给定的8字节数据类型? 我如何用C和C ++编程呢?
答案 0 :(得分:1)
前言,我将向您展示如何在C ++中执行
虽然看起来您应该只使用位域来实现这一点,但由于必须按位元素初始化位域,因此无法使用位域。在c ++中查看更多here on how to use bitfields。要了解为什么要尝试执行以下操作:
struct S{
std::uint32_t x : 16;
std::uint32_t y : 16;
}
// 65536 = 0001 0000 0000 0000 0000 in binary
S s = {65536};
std::cout << s.x << std::endl;
std::cout << s.y << std::endl;
// >>> 0
// >>> 0
// since the first parameter actually only initializes x, and not y.
//you also cannot do the following
S s = 65536 // Error! no conversion between S and uint32_t!
哇,我怎么把基本类型设置为位字段呢!要解决这个问题,我们需要使用unions。我将向您展示使用联合解决此问题的最简单答案,然后使用anonymous unions and structures链接到更复杂但更紧凑的解决方案。
这基本上是您需要为您的问题做的事情:
struct nibble64bitField{
uint64_t A:4;
uint64_t B:4;
uint64_t C:4;
uint64_t D:4;
uint64_t E:4;
uint64_t F:4;
uint64_t G:4;
uint64_t H:4;
uint64_t I:4;
uint64_t J:4;
uint64_t K:4;
uint64_t L:4;
uint64_t M:4;
uint64_t N:4;
uint64_t O:4;
uint64_t P:4;
};
union split8bytes{
std::uint64_t integer;
nibble64bitField bitfield;
};
int main() {
// note this is 255 + 256, or 0000 1111 1111 + 0001 0000 0000
uint64_t eightbyte_value = 511;
split8bytes split = {eightbyte_value};
std::cout << split.bitfield.A << " should be 15" << std::endl;
std::cout << split.bitfield.B << " should be 15" <<std::endl;
std::cout << split.bitfield.C << " should be 1" << std::endl;
std::cout << split.bitfield.D << " should be 0" << std::endl;
std::cout << split.integer << " should be 511" << std::endl;
return 0;
}
在这里你使用了工会。现在为什么我们在这里使用工会?联合允许您将给定的union引用为union中的任何成员,但只占用与最大字节大小成员一样多的空间。这允许我们将splitbytes
设置为整数值,但是从该整数访问单个半字节(4位或半字节的组)。
正如所承诺的那样,另一个用户尝试在您的代码审查中尝试做同样的事情。他们的解决方案是手动执行此转换,另一个用户提供使用union struct范例进行转换(不是同一个问题,它不是重复的)。 Here匿名结构与编译器编译指示一起使用以确保打包(但仅限于某些编译器)
答案 1 :(得分:0)
由于@snb为您提供了C ++解决方案,因此这是一个C解决方案,使用数组:
union split8bit_u {
uint8_t byte;
struct {
uint8_t l_nyb:4;
uint8_t u_nyb:4;
};
};
typedef union split8bit_u split8bit;
union split64bit_u {
uint64_t lword;
split8bit byte[8];
};
typedef union split64bit_u split64bit;
int main() {
// note that 0x0123456789ABCDEF
split64bit data;
data.lword = 0x0123456789ABCDEF;
for ( int i = 0; i < sizeof(data); ++i) {
printf("%X.%X.",data.byte[i].l_nyb,data.byte[i].u_nyb);
}
printf("\b \n");
// Prints "F.E.D.C.B.A.9.8.7.6.5.4.3.2.1.0"
}
这将打印出16个离散的4位值。