Есть ли способ изменить способ хранения переменной в памяти (размер в битах)? - PullRequest
3 голосов
/ 11 июля 2011

Допустим, у меня есть следующая структура данных (псевдокод):

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

Теперь предположим, что я хочу, чтобы данные сохранялись в памяти следующим образом:

бит 7-6: идентификатор бит 5: сбой бит 4-0: значение

Есть ли способ сделать это в C / C ++ / Visual Studio? Я знаю, что ты можешь сделать это в Аде, но это не много значит.

Редактировать: Извините за непонятность, мне нужен определенный макет в памяти. Эта структура будет использоваться для сообщений, отправляемых по последовательному каналу, и должна соответствовать спецификации интерфейса

Ответы [ 5 ]

7 голосов
/ 11 июля 2011

Вы можете использовать битовые поля C:

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

Однако, хотя это может уменьшить объем памяти, используемой для структуры *, это не гарантирует какой-либо конкретной компоновки в памяти;конкретные биты, назначенные для каждого поля, будут зависеть от вашего компилятора и / или платформы ABI.Если вам нужно присвоить конкретные битовые индексы конкретным полям, вам нужно будет упаковать и распаковать вручную.Или, если ваш код не должен быть переносимым, вы можете посмотреть, как ваш компилятор упаковывает битовые поля, и соответствующим образом упорядочить элементы вашей структуры.

* - Стандарт C накладывает очень мало ограничений на компоновкубитовые поля, а C ++ еще меньше.Обычно это приводит к меньшему использованию памяти, но если компилятор решит, что наименьшая единица выделения битового поля, которую он будет использовать, это 32-битное поле или что-то еще, тогда размер может фактически увеличиться.См. ISO / IEC 9899: 1999 (E) §6.7.2.1 / 10

3 голосов
/ 11 июля 2011
struct
{
  int  id     :2;
  bool failure:1;
  int  value  :5;
} 
2 голосов
/ 11 июля 2011

Для ответа на необработанные данные вы, по сути, помещаете данные в 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,Вы хотите установить два старших разряда, битовая маска которых равна 0xC0.Конечно, вам нужно сдвинуть его на 6 битов, чтобы получить фактическое значение, в противном случае вы, например, получите 128 iso 2. Я сбросил маску, потому что на самом деле нет битов более высокого порядка, а bithsift удаляет младшие разряды.

Установка аналогична, вы хотите переопределить предыдущие данные, которые являются первой инструкцией (ox3F==00111111b), оператор and очищает части, которые являются 0 в маске, и не касается других битов.Инструкция 2 использует оператор или для установки (ранее очищенных) старших битов в новое значение и оставляет оригиналы нетронутыми, так как младшие биты равны 0 и a|0==a.

Другие частипохожи, надеюсь, что это поможет вам в пути ....

Итак, в итоге, извлечение означает "применение маски и сдвига битов", сохранение - "очистка битов с помощью & и сохранение битов с помощью |".Конечно, все становится сложнее, когда вы передаете многобайтовые значения (необходимо учитывать порядок байтов).

0 голосов
/ 11 июля 2011

Существуют специфичные для платформы способы создания структуры пакета таким образом.Если вы хотите следовать спецификации, вам нужно будет упаковать ее вручную в буфер uint8 или тому подобное.Компилятор будет учитывать размер полей в других предлагаемых решениях, но может упаковать их внутри структуры любым способом, который он выберет.Например, он может поместить неиспользуемый отступ между полями структуры для оптимизации скорости.

0 голосов
/ 11 июля 2011

Это должно быть возможно с использованием битовых полей. В этом конкретном случае код 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 для получения дополнительной информации или Google для битовых полей C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...