У меня есть структура 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 в этом случае?» Для осмысленного ответа пока недостаточно данных
@dbush Нет, можно изменить. Я просто хочу поставить состояние BOOL32; и options_select_t сел; внутри зарезервированного массива [2].
Как насчет: enum { RSVP_BOOL = 0, RSVP_SEL = 1 };
, а затем либо ptr->reserved[RSVP_BOOL] = (mybool ? 1 : 0);
, либо ptr->reserved[RSVP_SEL] = mysel;
Самый надежный способ - просто использовать информацию компилятора:
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
, чтобы помочь с вычислениями.
Это работает только потому, что между 3 полями в исходной структуре не было заполнения. Но если бы был отступ, он был бы (удален.
@ChrisDodd Я знаю об этом. Вот почему я включаю статические утверждения, которые проверяют
@RemyLebeau Как я уже сказал, я решил, что добавления статических утверждений достаточно.
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;
Чего ждать. Это изменяет все размеры и смещения. Почему битовые поля?
он хочет, чтобы оба были зарезервированы[2]. Нет другого варианта
А, теперь я вижу, как ты неправильно это понял. Это креативно, но я думаю, что это не то, что на самом деле имел в виду ОП. Удалил мой -1, хотя - это справедливое, но тупое прочтение - дружелюбно тупого - вопроса
@sehe сомнительно, кто неправильно понял.
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;
То, что вы опубликовали для
BOOL32
, на самом деле является определениемFScallback_t
, которое является указателем на функцию, возвращающуюBOOL32
.