Добавлять элементы внутри typedef, заботясь об общем размере структуры?

У меня есть структура typedef, которая в настоящее время выглядит так:

typedef struct Sys_Inject
{
   uint16_t num;
   uint16_t alternative;
   uint8_t  delay;
   uint8_t  thresh;
   uint8_t  reserved[2];
   BOOL32   state;
   options_select_t sel;
   uint32_t per;
} Sys_Inject_t;

Я хочу избавиться от элементов BOOL32 state; и options_select_t sel; и определить их внутри массива uint8_t reserved[2] так, чтобы reserved[0] = state и reserved[1] = sel. BOOL32 определяется в другом модуле как:

typedef BOOL32 (*FScallback_t)(uint32_t);

Также options_select_t является перечислением и определяется как:

typedef enum options_select_e
{
    TEST_DEFAULT = 0,
    TEST_CURRENT,
    TEST_SAVED,
}options_select_t;

Каков реальный размер BOOL32 в этом случае? Это 32 бита? Кроме того, размер перечисления 8 бит для каждого элемента?

Обратите внимание, что reserved — это массив из двух элементов, то есть всего 16 бит. Как мне поместить в него два элемента state и sel?

То, что вы опубликовали для BOOL32, на самом деле является определением FScallback_t, которое является указателем на функцию, возвращающую BOOL32.

dbush 13.12.2020 01:36

Кроме того, откуда это? Похоже, это часть какой-то библиотеки, и если это так, то, вероятно, это не то, к чему стоит прикасаться.

dbush 13.12.2020 01:37

«Каков фактический размер BOOL32 в этом случае?» Для осмысленного ответа пока недостаточно данных

Igor Tandetnik 13.12.2020 01:38

@dbush Нет, можно изменить. Я просто хочу поставить состояние BOOL32; и options_select_t сел; внутри зарезервированного массива [2].

Ashish101 13.12.2020 01:41

Как насчет: enum { RSVP_BOOL = 0, RSVP_SEL = 1 };, а затем либо ptr->reserved[RSVP_BOOL] = (mybool ? 1 : 0);, либо ptr->reserved[RSVP_SEL] = mysel;

Craig Estey 13.12.2020 04:48
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
125
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Самый надежный способ - просто использовать информацию компилятора:

typedef struct Sys_Inject {
    uint16_t num;
    uint16_t alternative;
    uint8_t delay;
    uint8_t thresh;
    uint8_t reserved[2 + sizeof(BOOL32) + sizeof(options_select_t)];
    uint32_t per;
} Sys_Inject_t;

Вот программа, которая статически проверяет это:

  • структура поддерживает тот же размер
  • смещение члена per в структуре остается таким же после

Прямой эфир на Колиру

#include <cstdint>
#include <cstddef>

enum BOOL32 : uint32_t { FALSE, TRUE };

enum options_select_t {
    TEST_DEFAULT = 0,
    TEST_CURRENT,
    TEST_SAVED,
};

struct OLD_Sys_Inject {
    uint16_t num;
    uint16_t alternative;
    uint8_t delay;
    uint8_t thresh;
    uint8_t reserved[2];
    BOOL32 state;
    options_select_t sel;
    uint32_t per;
};

typedef struct Sys_Inject {
    uint16_t num;
    uint16_t alternative;
    uint8_t delay;
    uint8_t thresh;
    uint8_t reserved[2 + sizeof(BOOL32) + sizeof(options_select_t)];
    uint32_t per;
} Sys_Inject_t;

static_assert(sizeof(OLD_Sys_Inject) == sizeof(Sys_Inject));
static_assert(offsetof(OLD_Sys_Inject, per) == offsetof(Sys_Inject, per));

int main() {}

Чтобы учесть любое потенциальное заполнение выравнивания между reserved[] и state или между state и sel, я бы, вероятно, использовал что-то вроде этого: uint8_t reserved[2 + (offsetof(OLD_Sys_Inject, per) - offsetof(OLD_Sys_Inject, reserved[2]))]; Или, может быть, использовал std::aligned_storage, чтобы помочь с вычислениями.

Remy Lebeau 13.12.2020 03:00

Это работает только потому, что между 3 полями в исходной структуре не было заполнения. Но если бы был отступ, он был бы (удален.

Chris Dodd 13.12.2020 03:09

@ChrisDodd Я знаю об этом. Вот почему я включаю статические утверждения, которые проверяют

sehe 13.12.2020 03:10

@RemyLebeau Как я уже сказал, я решил, что добавления статических утверждений достаточно.

sehe 13.12.2020 03:12
typedef struct Sys_Inject
{
   uint16_t num;
   uint16_t alternative;
   uint8_t  delay;
   uint8_t  thresh;
   union 
   {
        uint8_t  reserved[2];
        struct 
        {
            uint8_t state: 1;
            options_select_t sel: 2;
        };
   };
   uint32_t per;
} Sys_Inject_t;

или

typedef struct Sys_Inject
{
   uint16_t num;
   uint16_t alternative;
   uint8_t  delay;
   uint8_t  thresh;
   union 
   {
        uint8_t  reserved[2];
        struct 
        {
            uint8_t state: 1;
            uint8_t :7;
            options_select_t: 8;
        };
   };
   uint32_t per;
} Sys_Inject_t;

Чего ждать. Это изменяет все размеры и смещения. Почему битовые поля?

sehe 13.12.2020 01:57

он хочет, чтобы оба были зарезервированы[2]. Нет другого варианта

0___________ 13.12.2020 01:59

А, теперь я вижу, как ты неправильно это понял. Это креативно, но я думаю, что это не то, что на самом деле имел в виду ОП. Удалил мой -1, хотя - это справедливое, но тупое прочтение - дружелюбно тупого - вопроса

sehe 13.12.2020 02:03

@sehe сомнительно, кто неправильно понял.

0___________ 13.12.2020 02:04

BOOL32, скорее всего, 32-битный, учитывая его название. Но вы не показали объявление для BOOL32, вы фактически показали объявление FScallback_t, которое является указателем на функцию, возвращающую BOOL32.

Размер options_select_t определяется компилятором. Это может быть 1 байт, а может быть 2 байта, а может быть 4 байта и т. д. Невозможно ответить на этот вопрос, не зная, какой компилятор вы используете и какие параметры вы указываете при компиляции кода с его помощью.

Но в любом случае reserved имеет размер всего 2 байта. Невозможно вписать state в reserved[0], если BOOL32 больше 8 бит, или вписать sel в reserved[1], если options_select_t больше 8 бит. Не стоит и пытаться. Предполагая, что вам нужно сохранить тот же размер оригинала Sys_Inject_t, вам нужно будет расширить размер reserved, чтобы включить размеры BOOL32 и options_select_t, например.

typedef struct Sys_Inject
{
   uint16_t num;
   uint16_t alternative;
   uint8_t  delay;
   uint8_t  thresh;
   uint8_t  reserved[2 + sizeof(BOOL32) + sizeof(options_select_t) + any padding that was present between the original fields];
   uint32_t per;
} Sys_Inject_t;

Другие вопросы по теме