有没有办法改变变量在内存中的存储方式(位大小)?

时间:2011-07-11 19:12:39

标签: c++ c visual-studio serial-port

假设我有以下数据结构(伪代码):

struct
{
  uint8  id;
  bool   failure;
  uint8  value;
}  

现在假设我希望数据以如下方式存储在内存中:

第7-6位:id 第5位:失败 位4-0:值

有没有在C / C ++ / Visual Studio中这样做?我知道你可以在Ada做到这一点,但这并不意味着什么。

编辑:抱歉不清楚,我确实需要内存中的特定布局。此结构将用于通过串行通道发送的消息,并且需要符合接口规范

5 个答案:

答案 0 :(得分:7)

您可以使用C位域:

struct
{
  uint8 id : 2;
  bool failure : 1;
  uint8 value : 5;
};

但是,虽然这个可能减少了用于struct *的内存量,但这并不保证任何特定的内存布局;为每个字段分配的特定位将取决于您的编译器和/或平台ABI。如果需要将特定位索引分配给特定字段,则需要手动打包和解压缩。或者,如果您的代码不需要是可移植的,您可以查看编译器如何打包位域,并相应地对结构的成员进行排序。

* - C标准对位域布局的限制很少,而C ++甚至更少。通常它会导致较少的内存使用,但如果编译器决定它将使用的最小位域分配单元是32位字段或其他东西,那么大小实际上可能会增加。见ISO / IEC 9899:1999(E)§6.7.2.1/ 10

答案 1 :(得分:3)

struct
{
  int  id     :2;
  bool failure:1;
  int  value  :5;
} 

答案 2 :(得分:2)

对于原始数据答案,您基本上将数据放在uint8_t中并使用位掩码和位移来提取数据,示例实现可能是:

class MyData
{
private:
    uint8_t data;

public:
    MyData() : data(0) {}
    MyData(uint8_t id, bool failure, uint8_t value) : data(0)
    {
        Id(id);
        Failure(failure);
        Value(value);
    }

    uint8_t Id()
    {
        return (data>>6);
    }

    void Id(uint8_t id)
    {
        data &= 0x3F;
        data |= ((id&0x3)<<6);
    }

    bool Failure()
    {
        return (data & 0x20);
    }

    void Failure(bool failure)
    {
        if(failure)
        {
            data |= 0x20;
        }
        else
        {
            data &= 0xDF;
        }
    }

    uint8_t Value()
    {
        return (data & 0x0F);
    }

    void Value(uint8_t val)
    {
        data &= 0xF0;
        data|=(val&0xF);
    }

};

让我们以Id为例,你想设置两个最高位,bitmasked这是0xC0。当然你要用6位向下移动它来得到实际值,否则你会得到128 iso 2.我放弃了掩码,因为实际上没有更高阶位,而bithsift删除了更低阶。

设置它是类似的,你想要覆盖以前的数据,即指令1(ox3F==00111111b),和运算符清除掩码中0的部分而不触及其他位。指令2使用或运算符将(先前已清除的)高位设置为新值,并保持原始状态不变,因为低位为0且a|0==a

其他部分类似,希望这可以帮助你......

如此总结,检索是“应用掩码和位移”,存储是“用&amp;清除位并用|”存储位。当然,一旦传递多字节值,事情会变得更复杂(你必须考虑到字节序)。

答案 3 :(得分:0)

这应该可以使用位字段。在这种特定情况下,C ++代码将是:

struct
{
    uint8  value : 5; // bits 0-4
    bool   failure : 1; // bit 5
    uint8  id : 2; // bit 6-7
};

注意:请务必检查编译器文档,因为位排序和内存填充可能会影响可移植性。有关详细信息,请参阅http://en.wikipedia.org/wiki/Bit_field;有关C ++位字段,请参阅google。

答案 4 :(得分:0)

有一些特定于平台的方法来制作结构包。如果您想遵循规范,则必须手动将其打包到uint8缓冲区等。编译器将尊重其他提议的解决方案中字段的大小,但可以按照其选择的方式将它们打包在结构内部。例如,它可以在结构的字段之间放置未使用的填充以进行速度优化。