c++, struct

Тема в разделе "WASM.BEGINNERS", создана пользователем semishift, 4 фев 2011.

  1. semishift

    semishift Сергей

    Публикаций:
    0
    Регистрация:
    6 фев 2010
    Сообщения:
    6
    вопрос: имеется такой фрагмент

    Код (Text):
    1. struct Option {
    2.     const char * const Name;
    3.     int Value;
    4. };
    5.  
    6. struct Settings {
    7.     Option ScreenWidth;
    8.     Option ScreenHeight;
    9. };
    можно ли как-то обращаться к полям структуры Settings как к элементам массива, допустим при сохранении ее в ini файл?
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Почему нет?
     
  3. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Ты в файл его не сохранишь.
    Придумывай другую структуру.
    Name - это указатель, адрес в памяти.
    Сохрани в файл, перезапусти приложение и считай из файла - по этому адресу будет мусор.
    Нужно сохранять сами значения, а не адрес в памяти.

    Насчёт массивов - не понятно чего ты хотел.
    Массив структур Settings? Можно, а почему нет?
     
  4. semishift

    semishift Сергей

    Публикаций:
    0
    Регистрация:
    6 фев 2010
    Сообщения:
    6
    cppasm
    думаю, в моем случае не будет, образ грузится по фиксированному адресу, смещения строк в нем постоянны.

    я имел в виду, возможно ли написать что-то похожее на
    Код (Text):
    1. struct Option {
    2.     const char * const Name;
    3.     int Value;
    4. };
    5.  
    6. struct Settings {
    7.     Option ScreenWidth;
    8.     Option ScreenHeight;
    9. };
    10.  
    11. Settings SModified;
    12.  
    13. for (int i=0; i<sizeof(Settings)/sizeof(Option); i++) fprintf(file, "%s=%i\n", SModified[i].Name, &SModified[i].Value);
     
  5. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Возможно.
     
  6. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    пишите, кто вам мешает... только вы написали неправильно и это канеш плохой стиль, нормальные программисты так не пишут... SModified, если бы он был у вас указателем ... то SModified[1] - будет за уже структурой (тк размер структуры Settings больше размера структуры Option)... надо преобразовать указатель Settings к указателю на Option... и амперсанд перед SModified.Value не понятно зачем поставлен...
     
  7. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    вот так примерно:
    Код (Text):
    1. struct Option {
    2.     const char * const Name;
    3.     int Value;
    4. };
    5.  
    6. struct Settings {
    7.     Option ScreenWidth;
    8.     Option ScreenHeight;
    9. };
    10.  
    11. Settings SModified;
    12.  
    13. Option* opt = (Option*)&SModified;
    14. for (int i=0; i<sizeof(Settings)/sizeof(Option); i++)
    15. { fprintf(file, "%s=%i\n", opt[i].Name, opt[i].Value); }
    и на злобу дня: это все справедливо, если обе структуры являются pod-типами, хотя они скорее всего ими будут...
     
  8. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Фиговый это метод, выравнивание может всё поломать и POD-типы не спасут.
    Если нужен массив, чего не сделать массив?
    Код (Text):
    1. struct Settings {
    2.     Option Options[CONST_NUM];
    3. };
    А если загрузится по другому адресу, а если строки динамические?
    Короче плохо так писать.
     
  9. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    cppasm
    Элементы массивов и мемберы структур выравниваются по разному? Впервые такое слышу.
     
  10. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    не-не-не)

    PE-файл без релоков не загрузится по другому адресу... при сохранении строк никаких проблем не может возникнуть... при загрузке - другой вопрос, они уже в секции данных, грузить строку надо в отдельный буффер и искать адрес на нее в памяти... хотя если параметры всегда пишутся одинакого, то можно их вообще не грузить... а вообще ТС неплохо бы подучить язык, чтоб не возникало таких вопросов и чтобы не генерить гуано-код... ну или перейти на си-шарп/руби/питон...
     
  11. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    На испытанных компиляторах - нет, они всячески этому противостоят :)
    По стандарту элементы массива обязательно идут последовательно (без промежутков), а между полями структуры может добавляться выравнивание.
    Вот смоделированная ситуация для gcc:
    Код (Text):
    1. struct OPTION
    2. {
    3.     int  id;
    4.     char data;
    5. } __attribute__((packed));
    6. typedef struct OPTION OPTION;
    7.  
    8. struct SETTINGS_ARR
    9. {
    10.     OPTION  options[4] __attribute__((aligned(8)));
    11. };
    12. typedef struct SETTINGS_ARR SETTINGS_ARR;
    13.  
    14. struct SETTINGS_STR
    15. {
    16.     OPTION  option1 __attribute__((aligned(8)));
    17.     OPTION  option2 __attribute__((aligned(8)));
    18.     OPTION  option3 __attribute__((aligned(8)));
    19.     OPTION  option4 __attribute__((aligned(8)));
    20. };
    21. typedef struct SETTINGS_STR SETTINGS_STR;
    22.  
    23. int main(void)
    24. {
    25.     printf("sizeof(OPTION)=%d\n"
    26.            "sizeof(SETTINGS_ARR)=%d\n"
    27.            "sizeof(SETTINGS_STR)=%d\n",
    28.             sizeof(OPTION),
    29.             sizeof(SETTINGS_ARR),
    30.             sizeof(SETTINGS_STR));
    31.     return 0;
    32. }
    Вывод:
    Напишу сразу - понятно что я это сделал намеренно чтобы показать что я имею ввиду, т.е. ситуация довольно искусственная.
    Если вручную не задавать выравнивания, компилятор всячески пытается недопустить этой ситуации и в основном просто выравнивает размер структуры sizeof(OPTION)=8, хотя этого и не требуется (при sizeof(OPTION)=5 все поля структуры имеют то же выравнивание).

    Это понятно.
    Просто это куча ограничений, зачем такой код писать?
    Сохранять надо данные, а не адрес в памяти, который в общем случае при разных запусках будет разным.
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    cppasm
    Выравнивание делается для оптимизации по скорости, а раз так, то нет разницы структура это или массив. Насчёт промежутков я не понял, выравнивание это не промежутки.
     
  13. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    std::map<std::string,int> settings;
    settings["ScreenWidth"] = 80;
    settings["ScreenHeight"] = 25;
     
  14. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Во-первых - выравнивание это "промежутки", добавление "пустых" байтов для получения адреса следующего поля кратного определённому числу.
    Вот пример:
    Код (Text):
    1. struct TEST
    2. {
    3.     char x;
    4.     int   y;
    5. };
    При включённом выравнивании данные будут расположены так:
    x - 1 байт
    alignment - 3 байта для выравнивания, не используется (это я назвал промежутком)
    y - 4 байта

    Есть разница структура это или массив.
    Пусть есть упакованная структура:
    Код (Text):
    1. struct TEST
    2. {
    3.     int i_val;
    4.     char c_val;
    5. };
    Размер будет 5 байт.
    Теперь если создать структуру, содержащую массив этих структур:
    Код (Text):
    1. struct COMPOUND
    2. {
    3.     struct TEST test_arr[2];
    4. };
    Выравниваться будет адрес test_arr, в самом массиве данные будут идти непрерывно:
    0 элемент: i_val 4 байта, c_val 1 байт
    1 элемент: i_val 4 байта, c_val 1 байт
    Если создать структуру с двумя вложенными структурами:
    Код (Text):
    1. struct COMPOUND
    2. {
    3.     struct TEST test1;
    4.     struct TEST test2;
    5. };
    Выравниваться будет адрес каждого поля структуры, т.е. адрес test1 и адрес test2.
    Получим
    test1: i_val 4 байта, c_val 1 байт
    alignment: 3 байта для выравнивания адреса test2 на границу двойного слова
    test2: i_val 4 байта, c_val 1 байт

    Разницу видишь?
    Расположение в памяти будет разное.
    Для массива гарантируется что элементы идут последовательно, между ними данные для выравнивания добавляться не могут.
    А между полями структуры - могут.
     
  15. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    cppasm
    Вижу. ^). Ну нет, так нет.
     
  16. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Не, ну если он забивается на то, что у него исполняемый модуль всегда будет по одному и тому же адресу грузиться, то и твой метод использовать можно.
    Из всех компиляторов которые я протестировал все нормально эту ситуацию разруливают если вручную с выравниваением не извращаться.
    Просто стандартом это не гарантировано, и однажды можно наколоться.
     
  17. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    cppasm
    А если поиграться на одном и том же компиляторе с опциями компиляции/оптимизации? Вот тут-то всё и вскроется.
     
  18. ntkernelspawn

    ntkernelspawn New Member

    Публикаций:
    0
    Регистрация:
    17 дек 2010
    Сообщения:
    61
    По выравниванию от Мелкомягких есть #pragma pack

    struct Option {
    const char * const Name;
    int Value;
    };

    struct Settings {
    union {
    struct {
    Option ScreenWidth;
    Option ScreenHeight;
    };
    Option ArrayOption[2]; //На самом деле число здесь не имеет смысла.
    }
    };