Как инициализировать структуру в соответствии со стандартами языка программирования C

362

Я хочу инициализировать элемент структуры, разделить в декларации и инициализации. Вот что у меня есть:

typedef struct MY_TYPE {
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

void function(void) {
  MY_TYPE a;
  ...
  a = { true, 15, 0.123 }
}

Это способ объявить и инициализировать локальную переменную MY_TYPE в соответствии со стандартами языка программирования C (C89, C90, C99, C11 и т.д.)? Или есть что-нибудь лучше или хотя бы работает?

Обновление У меня был статический элемент инициализации, в котором я устанавливал каждый подэлемент в соответствии со своими потребностями.

  • 3
    Вы действительно должны принять лучший ответ, я вижу, что вам пришлось использовать какое-то плохое руководство по кодированию, но вы все равно не должны предлагать другим людям, что это правильный способ сделать это ..
  • 0
    @KarolyHorvath хорошо, большинство хороших ответов относятся к C99. Может быть, мой вопрос является дубликатом stackoverflow.com/questions/6624975/… ?
Показать ещё 4 комментария
Теги:
struct
initialization

14 ответов

595
Лучший ответ

В (ANSI) C99 вы можете использовать назначенный инициализатор для инициализации структуры:

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

Изменить: другие члены инициализируются как ноль: "Неиспользуемые члены поля неявно инициализируются так же, как объекты со статической продолжительностью хранения". (https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)

  • 77
    офигенно спасибо Вы можете даже вкладывать их в себя: static oxeRay2f ray = {.unitDir = {.x = 1.0f, .y = 0.0f}};
  • 2
    Это не отвечает на вопрос вообще. ОП хочет отделить инициализацию от декларации.
Показать ещё 2 комментария
161

Вы можете сделать это с помощью составного литерала. Согласно этой странице, он работает на C99 (который также считается ANSI C).

MY_TYPE a;

a = (MY_TYPE) { .flag = true, .value = 123, .stuff = 0.456 };
...
a = (MY_TYPE) { .value = 234, .stuff = 1.234, .flag = false };

Обозначения в инициализаторах являются необязательными; вы также можете написать:

a = (MY_TYPE) { true,  123, 0.456 };
...
a = (MY_TYPE) { false, 234, 1.234 };
  • 0
    Итак, назначенные инициализаторы предназначены для того, когда вы объявляете и определяете одновременно, а составные литералы - для того, когда вы определяете уже объявленную переменную?
  • 0
    @ Geremia, вы должны сначала определить структуру в обоих случаях, но с помощью назначенных инициализаторов вы сделаете код более читабельным и более устойчивым к ошибкам в случае изменений в структуре.
Показать ещё 1 комментарий
78

Я вижу, что вы уже получили ответ о ANSI C 99, поэтому я брошу кость в ANSI C 89. ANSI C 89 позволяет инициализировать структуру следующим образом:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = { 5, 2.2, "George" };
    return 0;
}

Важно помнить, что в настоящий момент вы инициализируете даже один объект/переменную в структуре, все остальные переменные будут инициализированы значением по умолчанию.

Если вы не инициализируете значения в своей структуре, все переменные будут содержать "значения мусора".

Удачи!

  • 2
    Можно ли использовать переменные при инициализации?
  • 1
    @Cyan Это для объектов с автоматическим сроком хранения. См. 6.7.9 13) в open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf . Для глобальных объектов в значительной степени ограничивается литералами. Вы даже не можете использовать другие глобальные объекты, даже если они постоянны.
35

a = (MYTYPE){ true, 15, 0.123 };

будет отлично работать на C99

17

Вы почти получили его...

MY_TYPE a = { true,15,0.123 };

Быстрый поиск по 'struct initialize c' показывает мне это

  • 1
    Я думаю, что это верно для стандарта C, но не для ANSI C (99?). Кроме того, я связан с правилами кодирования, которые не позволяют мне одновременно выполнять декларирование и инициализацию, поэтому я должен разделить его и инициализировать каждый отдельный подэлемент.
  • 7
    Инициализация может произойти только в точке объявления. Вот что значит «инициализировать». В противном случае вы позволяете неопределенному значению быть начальным значением вашей переменной / структуры, а затем присваиваете значение позже.
Показать ещё 2 комментария
13

как сказал Рон Нуни:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = {5, 2.2, "George"};
    return 0;
}

Важно помнить: на данный момент вы инициализируете даже один объект/переменную в структуре, все остальные переменные будут инициализированы значением по умолчанию.

Если вы не инициализируете значения в своей структуре (т.е. если вы просто объявите эту переменную), все variable.members будут содержать "значения мусора", , только если объявление является локальным!

Если декларация глобальная или статическая (как в этом случае), все неинициализированные variable.members будут автоматически инициализированы:

  • 0 для целых чисел и с плавающей запятой
  • '\0' для char (конечно, это то же самое, что и 0, а char - целочисленный тип)
  • NULL для указателей.
  • 0
    Интересный к локальному / глобальному, это также относится к значениям структуры времени. У меня был местный, и в одном случае DST был включен, в другом - нет, не из-за того, что я сделал. Я не использовал DST (поле tm_isdst), это было из strptime, но когда я конвертировал в time_t, у некоторых был час отдыха.
12
Стандарт языка программирования

C ISO/IEC 9899: 1999 (обычно известный как C99) позволяет использовать инициализатор назначенный для инициализации членов структуры или объединения следующим образом

MY_TYPE a = { .stuff = 0.456, .flag = true, .value = 123 };

В разделе paragraph 7, раздел 6.7.8 Initialization стандарта ISO/IEC 9899: 1999 определено:

Если обозначение имеет форму
, идентификатор
то текущий объект (определенный ниже) должен иметь структуру или тип объединения, а идентификатор должен быть именем члена этого типа.

Обратите внимание, что paragraph 9 того же раздела гласит, что:

За исключением случаев, когда явно указано иное, для целей этого подпункта неназванные члены объектов структуры и типа объединения не участвуют в инициализации. Элементы-члены-члены структурных объектов имеют неопределенное значение даже после инициализации.

В реализации GNU GCC, однако опущенные элементы инициализируются как нулевые или нулевые значения типа. Как указано в разделе 6.27 Назначенные инициализаторы документации GNU GCC:

Неиспользуемые члены поля неявно инициализируются так же, как объекты, имеющие статическую продолжительность хранения.

Компилятор Microsoft Visual С++ должен поддерживать назначенные инициализаторы с версии 2013 согласно официальному сообщению в блоге С++ Conformance Roadmap. Параграф Initializing unions and structs статьи Инициализаторы в документации MSDN Visual Studio предполагает, что неназванные участники инициализируются нулевыми значениями аналогично GNU GCC.

Новый стандарт ISO/IEC 9899: 2011 (обычно известный как C11), который заменил ISO/IEC 9899: 1999, сохраняет назначенные инициализаторы в разделе 6.7.9 Initialization. Он также сохраняет paragraph 9 неизменным.

  • 2
    Первоначально я предложил это как правку принятому ответу, но он был отклонен. Таким образом я отправляю это как ответ.
4
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}
  • 8
    Будет ли это работать, если одно из полей квалифицировано как const ?
  • 21
    как только я услышал «инициализация отличается от назначения». так это не назначение, а не инициализация?
2

Я нашел другой способ инициализации структур.

Структура:

typedef struct test {
    int num;
    char* str;
} test;

Инициализация:

test tt = {
    num: 42,
    str: "nice"
};

В соответствии с документацией GCC этот синтаксис устарел после GCC 2.5.

2

Если MS не обновилась до C99, MY_TYPE a = {true, 15,0.123};

1

Мне не понравился ни один из этих ответов, поэтому я сделал свой собственный. Я не знаю, является ли это ANSI C или нет, это просто GCC 4.2.1 в нем по умолчанию. Я никогда не помню брекетинг, поэтому я начинаю с подмножества моих данных и сражаюсь с сообщениями об ошибках компилятора, пока он не закроется. Чтение - это мой первый приоритет.

    // in a header:
    typedef unsigned char uchar;

    struct fields {
      uchar num;
      uchar lbl[35];
    };

    // in an actual c file (I have 2 in this case)
    struct fields labels[] = {
      {0,"Package"},
      {1,"Version"},
      {2,"Apport"},
      {3,"Architecture"},
      {4,"Bugs"},
      {5,"Description-md5"},
      {6,"Essential"},
      {7,"Filename"},
      {8,"Ghc-Package"},
      {9,"Gstreamer-Version"},
      {10,"Homepage"},
      {11,"Installed-Size"},
      {12,"MD5sum"},
      {13,"Maintainer"},
      {14,"Modaliases"},
      {15,"Multi-Arch"},
      {16,"Npp-Description"},
      {17,"Npp-File"},
      {18,"Npp-Name"},
      {19,"Origin"}
    };

Данные могут начать жизнь в виде файла с разделителями табуляции, который вы заменяете, чтобы массажировать в нечто другое. Да, это материал Debian. Итак, одна внешняя пара {} (указывающая массив), затем другая пара для каждой структуры внутри. С запятыми между. Помещение вещей в заголовок не является строго необходимым, но у меня есть около 50 элементов в моей структуре, поэтому я хочу их в отдельном файле, чтобы сохранить беспорядок из моего кода, и поэтому его легче заменить.

  • 2
    Не было вопроса об инициализации массива структур! Я имею в виду, ваш ответ содержит накладные расходы.
  • 0
    Я предполагаю, что моей целью было объявление структуры со значениями уже в ней, а не использование = для установки каждого значения позже.
Показать ещё 1 комментарий
0

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

typedef struct {
    char *str;
    size_t len;
    jsmntok_t *tok;
    int tsz;
} jsmn_ts;

#define jsmn_ts_default (jsmn_ts){NULL, 0, NULL, 0}

Это можно использовать в коде как:

jsmn_ts mydata = jsmn_ts_default; /* initialization of a single struct */

jsmn_ts myarray[10] = {jsmn_ts_default, jsmn_ts_default}; /* initialization of
                                                    first 2 structs in the array */
  • 0
    Но это не инициализирует массив структур значениями по умолчанию. Он инициализирует первую структуру в массиве значениями, указанными в jsmn_ts_default , но остальные структуры инициализируются так, как если бы массив имел статическую продолжительность хранения, что означает, что члены инициализируются NULL и 0 . Но если вы измените на #define jsmn_ts_default (jsmn_ts){"default", sizeof "default", NULL, 0} вы увидите, что только первый элемент массива инициализируется таким образом.
  • 0
    Да, я только что вернулся из тестирования, хотел отредактировать пост :) Кстати, такое же поведение происходит с int a[10] = {1}; Только 1-й элемент будет ==1
0

Я прочитал документацию Microsoft Visual Studio 2015 для инициализации совокупных типов, но все формы инициализации с помощью {...} объясняются там, но здесь не упоминается инициализация с точкой с названием "обозначение". Это тоже не работает.

Стандартная глава C99 6.7.8 Инициализация объясняет возможность указателей, но, на мой взгляд, для сложных структур не совсем понятно. Стандарт C99 в формате pdf.

На мой взгляд, может быть лучше

  1. Используйте = {0}; -initialization для всех статических данных. Это меньше усилий для машинного кода.
  2. Использовать макросы для инициализации, например

    typedef MyStruct_t{ int x, int a, int b; } MyStruct; define INIT_MyStruct(A,B) { 0, A, B}

Макрос может быть адаптирован, его список аргументов может быть независимым от измененного содержимого структуры. Правильно, если нужно инициализировать меньшее количество элементов. Он также подходит для вложенной структуры. 3. Простая форма: Инициализация в подпрограмме:

void init_MyStruct(MyStruct* thiz, int a, int b) {
  thiz->a = a; thiz->b = b; }

Эта процедура выглядит как ObjectOriented в C. Используйте thiz, а не this чтобы скомпилировать ее с C++!

MyStruct data = {0}; //all is zero!
init_MyStruct(&data, 3, 456);
0

Структура в C может быть объявлена ​​и инициализирована следующим образом:

typedef struct book
{
    char title[10];
    char author[10];
    float price;
} book;

int main() {
    book b1={"DS", "Ajay", 250.0};

    printf("%s \t %s \t %f", b1.title, b1.author, b1.price);

    return 0;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню