在单个半字节(0-F)中,我可以存储0到15之间的一个数字。在一个字节中,我可以存储0到255之间的单个数字(00 - FF)。 我可以使用字节(00-FF)存储两个不同的数字,每个数字的范围是0-127(00 - 7F)吗?
答案 0 :(得分:10)
你的问题的答案是否定的。你可以将一个字节分成两个数字,但这两个数字中的位总和必须是< = 8.因为,0-127的范围需要7位,另一个数字在byte只能是1位,即0-1。
答案 1 :(得分:4)
由于明显的cardinality原因,您不能在0 ... 255范围的一个字节中存储0 ... 127范围内的两个小整数。换句话说,cartesian product [0; 127]×[0; 127]有2个 14 元素,大于2 8 ([2]的基数0; 255]间隔,对于字节)
(如果你能承受失去的精确度 - 你没有告诉 - 你可以,例如只存储最高位...)
也许你的问题是:我可以在一个字节中存储[0; 15]中的两个小整数吗?当然你可以:
typedef unsigned unibble_t; // unsigned nibble in [0;15]
uint8_t make_from_two_nibbles(unibble_t l, unibble_t r) {
assert(l<=15);
assert(r<=15);
return (l<<4) | r;
}
unibble_t left_nible (uint8_t x) { return x >> 4; }
unibble_t right_nibble (uint8_t) { return x & 0xf; }
但我认为你不应该那样做。首先,您可以使用struct
中的位字段。然后(并且最重要的是)以这种方式处理半字节可能比使用字节更低效并且使得代码可读性更低。
更新单个半字节,例如与
void update_left_nibble (uint8_t*p, unibble_t l) {
assert (p);
assert (l<=15);
*p = ((l<<4) | ((*p) & 0xf));
}
有时很昂贵(它涉及内存加载和内存存储,所以使用CPU cache和cache coherence机制),最重要的是通常是非atomic操作(什么如果两个不同的线程同时在{em>相同的地址update_left_nibble
上调用p
并且pointer aliasing - undefined behavior,那么会发生。
根据经验,避免在一个字节中包含多个数据项,除非您确定它是值得的(例如,您有十亿个这样的数据项)。
答案 2 :(得分:1)
对于0 ... 127中的两个值,一个字节是不够的,因为每个值都需要log 2 (128)= 7位,总共14个,但是一个字节只有8个位。
您可以使用C和C ++ 位域语法声明具有位打包存储的变量:
struct packed_values {
uint8_t first : 7;
uint8_t second : 7;
uint8_t third : 2;
};
在此示例中,sizeof(packed_values)
应该等于2,因为尽管有三个字段,但只使用了16位。
这比使用<<
和&
运算符的位运算更简单,但它与普通变量仍然不完全相同:位字段没有地址,所以你可以&# 39; t有一个指针(或C ++引用)。
答案 3 :(得分:0)
我可以使用一个字节来存储0-127范围内的两个数字吗?
当然你可以:
uint8_t storeTwoNumbers(unsigned a, unsigned b) {
return ((a >> 4) & 0x0f) | (b & 0xf0);
}
uint8_t retrieveTwoNumbers(uint8_t byte, unsigned *a, unsigned *b) {
*b = byte & 0xf0;
*a = (byte & 0x0f) << 4;
}
数字仍然在0 ... 127范围内(实际上是0 ... 255)。你只是松散了一些精度,类似于浮点类型。它们的值以16为增量递增。
答案 4 :(得分:-1)
您可以在单个字节中存储0到范围内的两个数据,但您不应该(一个var =一个数据是更好的设计)。
如果必须,您可以使用位掩码和位移来访问变量中的两个数据。
uint8_t var; /* range 0-255 */
data1 = (var & 0x0F); /* range 0-15 */
data2 = (var & 0xF0) >> 4; /* range 0-15 */