【问题标题】:Storing 8 logical true/false values inside 1 byte?在 1 个字节内存储 8 个逻辑真/假值?
【发布时间】:2015-07-03 13:01:59
【问题描述】:

我正在开发一个只有 2KB SRAM 的微控制器,并且迫切需要节省一些内存。试图弄清楚如何使用位域将 8 个 0/1 值放入单个字节,但无法完全解决。

struct Bits
{
    int8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

int main(){
    Bits b;
    b.b0 = 0;
    b.b1 = 1;

    cout << (int)b.b0; // outputs 0, correct
    cout << (int)b.b1; // outputs -1, should be outputting 1
}

什么给了?

【问题讨论】:

  • 你看过使用std::bitset
  • 你可以使用 unsigned 代替 int
  • 实际上,抛弃 C++ 并坚持使用 C 会显着减少内存使用量。没有那个,你的代码很好。 -1 是“真”。正如 Dieter 建议的那样,您也可以将您的字段设为无符号。
  • @LeeDanielCrocker,单独使用 b.b1 将评估为 true,但请注意 b.b1 == true。问我怎么知道....
  • 位域的定义应该使用'unsigned int8,而不是int8,否则每个位都会尝试成为符号位。导致困难。

标签: c++ bit-fields


【解决方案1】:

所有位域成员都是有符号的 1 位整数。在二进制补码系统上,这意味着它们只能表示0-1。如果需要01,请使用uint8_t

struct Bits
{
    uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

【讨论】:

  • NMDV,但在另一个 2 的补码系统上,int8_t b0:1 的值可能是 01?我在有符号的 1 位宽度位域上发现的信息很少。我在 C/C++ 规范中发现的关于带有位字段的 int8_t 的唯一内容是它是“实现定义的”类型。
  • @chux 如果可表示的值是 not 0 和 -1,则它不是 2s 补码表示。 (在 1s 补码或符号幅度表示的假设情况下,可表示的值将是 +0 和 -0,或者可能是 0 和 [trap 表示]。我不知道 any有符号整数格式,其中 1 位字段表示值 0 和 1。)
  • @zwol 同意:C 指定'符号位的值为 -(2^M)(二进制补码);" §6.2.6.2 2. 因此指定它必须是 0 或 @ 987654332@.
  • @chux 学究式地,二进制补码系统可以将int8_t 定义为char,然后将char 位域定义为无符号,因此程序仍然依赖于实现。事实上,常见的 ABI 指定了后者。前者取决于库的实现,并且在签名 char 时相当随意。
  • 请注意使用单个位。如果底层编译代码使用整个字节的读-修改-写来设置一个位,您可能会发现对这些位使用类似操作的中断处理程序可能会导致数据损坏。
【解决方案2】:

请注意 - 该标准并没有真正强制执行位域的实现方案。无法保证Bits 将是 1 个字节,假设它完全有可能更大。

然而,在实践中,实际的实现通常遵循明显的逻辑,它“几乎总是”大小为 1 字节,但同样,并不要求它得到保证。以防万一你想确定,你可以do it manually

顺便说一句 -1 仍然是 true 但它是 -1 != true

【讨论】:

  • 你能提供参考吗? Iirc 大小保证订单不
  • @Alex - 我似乎没有找到任何关于保证尺寸的信息。
  • 我认为大小是安全的(但实现不需要支持除intunsigned int 之外的任何东西):“实现可以分配任何足够大的可寻址存储单元以持有一个位域。如果有足够的空间,结构中紧跟在另一个位域之后的位域应该被打包到同一单元的相邻位中。我认为这意味着如果实现允许 8 位类型的位域,那么 OP 的代码就可以了。
【解决方案3】:

如上所述,这些变量仅包含一个符号位,因此唯一可用的值是 0-1

更适合这些位域的类型是bool。 C++14 §9.6/4:

如果值truefalse 存储到任何大小的bool 类型的位域(包括一位位域),则原始bool 值和该位的值-field 应该比较相等。

是的,std::uint8_t 可以完成这项工作,但您最好使用最合适的。你不需要像 std::cout &lt;&lt; (int)b.b0; 的演员表这样的东西。

【讨论】:

  • bool 不需要是 1 个字节,std::uint8_t 是。
  • @black 位域类型的大小不一定与结构体的大小有关。无论如何,在小型微控制器上,bool 很可能是 1 个字节。
【解决方案4】:

有符号和无符号整数就是答案。

请记住,信号只是对位的解释,-1 或 1 只是解释“变量类型”的“打印”序列化程序,因为它被编译器“揭示”给 cout 函数(查看运算符重载),位是相同的,它的值也是(开/关) - 因为你只有 1 位。

不关心这个,但明确的做法是一个好习惯,所以最好用无符号声明你的变量,它指示编译器在你设置或获取序列化器的值时挂载正确的代码,如“print " (cout)。

“COUT”运算符过载: “cout”通过一系列函数工作,参数重载指示编译器调用哪个函数。因此,有两个函数,一个接收无符号函数,另一个接收有符号函数,因此它们可以不同地解释相同的数据,您可以更改它,指示编译器使用强制转换调用另一个函数。见cout << myclass

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 2023-01-26
    • 2014-02-13
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多