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

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

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 и т. д.)? Или есть что-нибудь лучше или хотя бы работает?

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

16 ответов

Решение

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

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

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

Вы можете сделать это с составным литералом. Согласно этой странице, он работает в 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 };

Я вижу, вы уже получили ответ об 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;
}

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

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

Удачи!

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

будет хорошо в C99

Вы почти получили это...

MY_TYPE a = { true,15,0.123 };

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

Стандарт языка программирования 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 C++ должен поддерживать указанные инициализаторы с версии 2013, согласно официальному сообщению в блоге C++ Conformance Roadmap. Параграф Initializing unions and structs В статье Initializers в MSDN Visual Studio документация предполагает, что неназванные элементы инициализируются равными нулю соответствующими значениями аналогично GNU GCC.

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

Добавив ко всему этому хороший ответ, краткое изложение того, как инициализировать структуру (объединение и массив) в C, с особым вниманием к Designed Initializer.

Стандартная инициализация

      struct point 
{
    double x;
    double y;
    double z;
}

p = {1.2, 1.3}; 

Назначенный инициализатор

Назначенный инициализатор появился со времен ISO C99 и представляет собой другой и более динамичный способ инициализации в C при инициализации. struct, union или array.

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

Из Руководства GNU :

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

В ISO C99 вы можете указать элементы в случайном порядке, указав индексы массива или имена полей структуры, к которым они применяются, и GNU C позволяет это как расширение в режиме C90.


Примеры

1. Индекс массива

Стандартная инициализация

      int a[6] = { 0, 0, 15, 0, 29, 0 };

Назначенная инициализация

      int a[6] = {[4] = 29, [2] = 15 }; // or
int a[6] = {[4]29 , [2]15 }; // or
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

2. Структура или союз:

Стандартная инициализация

      struct point { int x, y; };

Назначенная инициализация

      struct point p = { .y = 2, .x = 3 }; or
struct point p = { y: 2, x: 3 };

3. Объедините элементы именования с обычной инициализацией последовательных элементов C:

Стандартная инициализация

      int a[6] = { 0, v1, v2, 0, v4, 0 };

Назначенная инициализация

      int a[6] = { [1] = v1, v2, [4] = v4 };

4. Другое:

Маркировка элементов инициализатора массива

      int whitespace[256] = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
                        ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };

напишите серию указателей '.fieldname' и '[index]' перед '=', чтобы указать вложенный подобъект для инициализации

      struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };

Гиды

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

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 для указателей.

Мне не понравился ни один из этих ответов, поэтому я сделал свой собственный. Я не знаю, является ли это 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 элементов, поэтому я хочу, чтобы они были в отдельном файле, чтобы не допустить путаницы в моем коде, и поэтому их легче заменить.

Сделать это можно разными способами:

MY_TYPE a = { true, 1, 0.1 };

MY_TYPE a = { .stuff = 0.1, .flag = true, .value = 1 }; //designated initializer, not available in c++

MY_TYPE a;
a = (MY_TYPE) { true,  1, 0.1 };

MY_TYPE m (true, 1, 0.1); //works in C++, not available in C

Кроме того, вы можете определить член при объявлении структуры.

#include <stdio.h>

struct MY_TYPE
{
    int a;
    int b;
}m = {5,6};

int main()
{
    printf("%d  %d\n",m.a,m.b);    
    return 0;
}
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}

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

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

Структура:

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

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

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

Согласно документации GCC, этот синтаксис является устаревшим с GCC 2.5.

Структура в 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;
}

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

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

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

  1. Использовать = {0};-инициализация для всех статических данных. Это меньше усилий для машинного кода.
  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);

Я искал хороший способ инициализации моей структуры, и я должен использовать ниже (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 */
Другие вопросы по тегам