Невозможно инициализировать struct вложенными указателями на другие структуры

#c #struct #initialization #nested

#c #struct #инициализация #вложенный

Вопрос:

Я использую стороннюю библиотеку, которая определяет эту структуру:

 typedef struct
{
    unsigned short nbDetectors;
    //! structure of detector status
    struct DetectorStatus
    {
        unsigned int lastError;         //< last detector internal error
        float temperature;              //< detector temperature
        detector_state state;           //< detector state
        unsigned short mode;            //< detector mode

        struct EnergyStatus
        {
            power_source powerSource;           //< front-end power source
            frontend_position frontendPosition; //< front-end position relative to the docking station

            struct BatteryStatus
            {
                bool present;                   //< battery present or not in the detector
                unsigned short charge;          //< charge level of the battery (in %)
                float voltageLevel;             //< battery voltage level
                float temperature;              //< temperature of the battery
                unsigned short chargeCycles;    //< number of charge/discharge cycles
                unsigned short accuracy;        //< Expected accuracy for charge level (in %)
                bool needCalibration;

            } batteryStatus;

        } * energyStatus;

        struct GridStatus
        {
            detector_grid grid;

        } * gridStatus;

    } * detectorStatus;

} HardwareStatus;
  

Эта структура используется библиотекой в качестве данных, передаваемых одним из ее обратных вызовов. Так что это библиотека, которая заполняет ее, я только что прочитал ее. Пока все хорошо.

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

Я попробовал это:

 HardwareStatus status;
status.detectorStatus->temperature = 20   rand() % 10;
e.data = amp;status;
m_pContext->EventCallback( EVT_HARDWARE_STATUS, amp;e );
  

Когда я скомпилировал, я получил:

 warning C4700: uninitialized local variable 'status' used
  

Тогда я понял… Указатели внутри struct указывают на мусор, хороший улов Visual Studio! Итак, я попытался начать с объявления экземпляра самой внутренней struct ( BatteryStatus ) , но это не скомпилировалось… потому что это не typedef’d (в нем говорится BatteryStatus , что тип не определен)? Итак, я попал в тупик… Как мне заполнить структуру?

Комментарии:

1. Кроме того, чтобы установить BatteryStatus, вам нужно будет написать EnergyStatus::BatteryStatus s; status.batteryStatus = s; Примечание о квалификации EnergyStatus::...

Ответ №1:

если вы хотите иметь все в стеке, это должно сделать это:

 // Getting structs on the stack initialized to zero
HardwareStatus status = { 0 };
HardwareStatus::DetectorStatus detectorStatus = { 0 };
HardwareStatus::DetectorStatus::EnergyStatus energyStatus = { 0 };
HardwareStatus::DetectorStatus::GridStatus gridStatus = { 0 };

// "Linking" structs
detectorStatus.energyStatus = amp;energyStatus;
detectorStatus.gridStatus = amp;gridStatus;
status.detectorStatus = amp;detectorStatus;

// Now you can fill and use them
status.detectorStatus->temperature = 20   3 % 10;
//...
  

Комментарии:

1. Это работает, но без нулей в инициализации структуры (я все еще не могу редактировать сообщения других людей). Спасибо!

2. Пожалуйста, обратите внимание, что это решение может быть очень опасным, если вы планируете использовать переменную ‘status’, «созданную» таким образом, за пределами области, в которой выполняются эти определения. Это потому, что он указывает внутренне на данные, размещенные в стеке, и этот стек исчезнет. Я бы посоветовал вам распределять память динамически.

3. @Lev: Это очень верно, и это не проблема, структура передается обратному вызову, и как только это будет сделано, в этом больше нет необходимости

4. @dario_ramos: если это ваш вариант использования, тогда все хорошо 🙂 Просто убедитесь, что не выполняете с ним никаких асинхронных действий.

Ответ №2:

Вы могли бы инициализировать его по значению:

 HardwareStatus status = {};
  

Если вы хотите создать экземпляр a BatteryStatus , вы можете сделать это, полностью указав имя:

 HardwareStatus::DetectorStatus::EnergyStatus::BatteryStatus bs;
  

Комментарии:

1. Это хорошее начало, более элегантное, чем memset’ting в 0, но… Я все еще не могу коснуться detectorStatus->temperature , потому detectorStatus что это недопустимый указатель

2. HardwareStatus status = {}; status.detectorStatus->temperature = 20 rand() % 10; Это скомпилировано для меня, кроме предупреждения о преобразовании int в float .

3. @Gnawme: ваш код присваивает значение через нулевой указатель. Почему вы ожидаете, что это сработает? То, что он строит, не означает, что это правильно.

4. @dario: Вы еще не создали экземпляр DetectorStatus for detectorStatus , на который можно указать!

5. @JohnDibling: я согласился с вашей инициализацией значения; Я должен был более внимательно прочитать вопрос OP…

Ответ №3:

вы пробовали memset’ing структуру в 0 ?

Комментарии:

1. memset(amp;status, 0, sizeof(status));

2. Что ж, это устраняет предупреждение, но теперь все указатели struct указывают на NULL (здесь 0)… Так что я все еще не могу установить detectorStatus->temperature (что на самом деле единственное, что я хочу сделать)