gpt4 book ai didi

c++ - 是否值得使用位移位将多个小数据成员存储在一个字节中?

转载 作者:太空宇宙 更新时间:2023-11-04 15:55:54 26 4
gpt4 key购买 nike

在 C++ 中,任何对象或原始数据类型的最小大小都是 1 个字节。但是,我经常使用只有几个可能值的枚举类型。它最近出现在我的一门类(class)的项目中,我必须存储许多包含两种不同的小型枚举类型的结构。因此,当然,我将枚举类型的基础类型设为 unsigned chars,并将结构设为每 2 个字节。

但是,由于每个枚举类型的可能值远少于 16 个,我意识到我可以使用位移来将它们存储在仅 1 个字节中。

这就是我所说的:

enum utensil : unsigned char {fork, spoon, spork};
enum dish : unsigned char {plate, bowl, box};
enum food : unsigned char {soup, salad, entree};
enum dessert: unsigned char {cake, ice_cream, fudge};

/* A class containing one of each of the four enums
above, but only taking up 1 byte of memory */

class TakeOut{
private:
unsigned char data = 0;

void clear_utensil(){
data = data & 0b00111111;
}
void clear_dish(){
data = data & 0b11001111;
}
void clear_food(){
data = data & 0b11110011;
}
void clear_dessert(){
data = data & 0b11111100;
}
public:
utensil get_utensil() const{
return utensil((data & 11000000) >> 6);
}
dish get_dish() const{
return dish((data & 00110000) >> 4);
}
food get_food() const{
return food((data & 00001100) >> 2);
}
dessert get_dessert() const{
return dessert(data & 00000011);
}
void set_utensil(utensil in){
clear_utensil();
data = data | ((unsigned char)(in) << 6);
}
void set_dish(dish in){
clear_dish();
data = data | ((unsigned char)(in) << 4);
}
void set_food(utensil in){
clear_food();
data = data | ((unsigned char)(in) << 2);
}
void set_dessert(utensil in){
clear_dessert();
data = data | (unsigned char)(in);
}
};

如果机会再次出现,我是否应该避免在“真实”项目中这样做?这当然很复杂,但如果我必须存储大量 TakeOut 对象,那么在访问数据成员时牺牲一点时间也许是值得的。

最佳答案

你不需要为此使用移位,你可以在结构中使用位域。这为您提供了相同的功能,但大大减少了输入(这意味着更少的维护、更少的错误和更多的乐趣!):

enum utensil_t : unsigned char {fork, spoon, spork};
enum dish_t : unsigned char {plate, bowl, box};
enum food_t : unsigned char {soup, salad, entree};
enum dessert_t: unsigned char {cake, ice_cream, fudge};

struct TakeOut {
utensil_t utensil : 2;
dish_t dish : 2;
food_t food : 2;
dessert_t dessert : 2;
};

但是,请注意,当您执行此操作时,您是在用性能换取规模,而且您很可能不希望进行此交易。除非你在一个非常受限的环境中处理很多这样的问题。

Language-lawyer note:从技术上讲,C++ 编译器不是需要打包位域,因为它们的布局是实现定义的。实际上,我认为在实践中没有任何不打包位域的实现。您可以通过以下方式轻松保护自己免受疯狂实现的影响:

static_assert(sizeof(TakeOut) == 1, "Sanity, please!");

关于c++ - 是否值得使用位移位将多个小数据成员存储在一个字节中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58087364/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com