如何利用未使用的位来节省内存?
How to save memory taking advantange of unused bits?
假设我有四个 unsigned char
变量,无论出于何种原因,在所有这些变量中,我从不使用最后一位,所以我有四位可以用于其他事情, 不需要额外的变量。
例如: example。如何使用以红色突出显示的那些位。
我认为我将不得不使用带位运算符的数学,但我不知道是否有任何正确或错误的方法。
注意:我正在尝试用 C 来做这个,所以如果你在这个例子中使用 C,我将非常感激,但我认为其他语言更胜一筹与 C 方法有很大不同。
你可以做一些移位,但你不会在内存方面节省太多,而且它会使你的代码更难阅读和理解。
您至少可以通过将这些值中的每一个放入具有位域的结构中来使它对您的代码更加透明:
struct vars {
unsigned int var1:7;
unsigned int var2:7;
unsigned int var3:7;
unsigned int var4:7;
unsigned int extra:4;
};
一般来说,C 提供了一个抽象机(以隐藏底层细节)并将您的代码转换成可能完全不同的东西。对于C抽象机; unsigned char
有 CHAR_BITS
位(可能不是 8 位),结构(包括位域)可能有任意数量的额外填充(无论编译器喜欢什么)等。
如果您关心底层细节;那你就得突破抽象。在您的情况下,这可能意味着(例如)使用 uint32_t
并进行移动和屏蔽自己;这样你就可以保证编译器把它转换成你想要的。
示例(未经测试且相对糟糕 - 可以使用定义和宏):
uint32_t demoPackedValue = ((uint32_t)'a' << 24) | ((uint32_t)'b' << 16) ((uint32_t)'c' << 8) | (uint32_t)'d';
char getChar1(uint32_t packedValue) {
return packedValue & 0x0000007FUL;
}
uint32_t setChar1(uint32_t packedValue, char c) {
packedvalue = (packedvalue & 0xFFFFFF80UL) | ((uint32_t)c);
return packedvalue;
}
int getBit1(uint32_t packedValue) {
return !!(packedValue & 0x00000080UL);
}
uint32_t setBit1(uint32_t packedValue, int value) {
if(value == 0) {
packedValue &= 0xFFFFFF7FUL;
} else {
packedValue |= 0x00000080UL;
}
return packedvalue;
}
char getChar2(uint32_t packedValue) {
return (packedValue & 0x00007F00UL) >> 8;
}
uint32_t setChar2(uint32_t packedValue, char c) {
packedvalue = (packedvalue & 0xFFFF80FFUL) | ((uint32_t)c << 8);
return packedvalue;
}
当然这也可能会损害性能(除非您有大量数据并且 shifting/masking 的额外成本是合理的)。
假设我有四个 unsigned char
变量,无论出于何种原因,在所有这些变量中,我从不使用最后一位,所以我有四位可以用于其他事情, 不需要额外的变量。
例如: example。如何使用以红色突出显示的那些位。
我认为我将不得不使用带位运算符的数学,但我不知道是否有任何正确或错误的方法。
注意:我正在尝试用 C 来做这个,所以如果你在这个例子中使用 C,我将非常感激,但我认为其他语言更胜一筹与 C 方法有很大不同。
你可以做一些移位,但你不会在内存方面节省太多,而且它会使你的代码更难阅读和理解。
您至少可以通过将这些值中的每一个放入具有位域的结构中来使它对您的代码更加透明:
struct vars {
unsigned int var1:7;
unsigned int var2:7;
unsigned int var3:7;
unsigned int var4:7;
unsigned int extra:4;
};
一般来说,C 提供了一个抽象机(以隐藏底层细节)并将您的代码转换成可能完全不同的东西。对于C抽象机; unsigned char
有 CHAR_BITS
位(可能不是 8 位),结构(包括位域)可能有任意数量的额外填充(无论编译器喜欢什么)等。
如果您关心底层细节;那你就得突破抽象。在您的情况下,这可能意味着(例如)使用 uint32_t
并进行移动和屏蔽自己;这样你就可以保证编译器把它转换成你想要的。
示例(未经测试且相对糟糕 - 可以使用定义和宏):
uint32_t demoPackedValue = ((uint32_t)'a' << 24) | ((uint32_t)'b' << 16) ((uint32_t)'c' << 8) | (uint32_t)'d';
char getChar1(uint32_t packedValue) {
return packedValue & 0x0000007FUL;
}
uint32_t setChar1(uint32_t packedValue, char c) {
packedvalue = (packedvalue & 0xFFFFFF80UL) | ((uint32_t)c);
return packedvalue;
}
int getBit1(uint32_t packedValue) {
return !!(packedValue & 0x00000080UL);
}
uint32_t setBit1(uint32_t packedValue, int value) {
if(value == 0) {
packedValue &= 0xFFFFFF7FUL;
} else {
packedValue |= 0x00000080UL;
}
return packedvalue;
}
char getChar2(uint32_t packedValue) {
return (packedValue & 0x00007F00UL) >> 8;
}
uint32_t setChar2(uint32_t packedValue, char c) {
packedvalue = (packedvalue & 0xFFFF80FFUL) | ((uint32_t)c << 8);
return packedvalue;
}
当然这也可能会损害性能(除非您有大量数据并且 shifting/masking 的额外成本是合理的)。