Создание глобальной "нулевой" структуры для повторного использования в программе на C? - PullRequest
1 голос
/ 07 ноября 2010

Не уверен, что я здесь делаю не так. У меня есть структура, которая интенсивно используется в моей программе.

typedef struct _MyStruct {
  // ... handful of non-trivial fields ...
} MyStruct;

Я ожидаю (прочитайте, намеревайтесь), чтобы многие части программы возвращали одну из этих структур, но многие из них должны иметь возможность возвращать "нулевую" структуру, которая является одиночной / глобальной. Точный вариант использования для реализации функции говорит: «Я не могу найти то, что вы просили меня вернуть».

Я предполагал, что это будет простой случай определения переменной в заголовочном файле и ее инициализации в файле .c.

// MyStruct.h

// ... Snip ...

MyStruct NotFoundStruct;

-

// MyStruct.c

NotFoundStruct.x = 0;
NotFoundStruct.y = 0;
// etc etc

Но компилятор жалуется, что инициализация не постоянна.

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

Но когда я сделаю это:

MyStruct thing = give_me_a_struct(some_input);
if (thing == NotFoundStruct) {
  // ... do something special
}

Th компилятор жалуется, что операнды бинарного оператора "==" (или "! =") Недействительны.

Как определить такую ​​структуру, как глобально повторно используемая (всегда один и тот же адрес памяти) структура?

Ответы [ 4 ]

9 голосов
/ 07 ноября 2010

Это не дает прямого ответа на ваш вопрос, но оно не помещается в комментарии ...

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

Один из вариантов - вернуть указатель, чтобы вы могли на самом деле вернуть NULL, чтобы указать, что вы действительно ничего не возвращаете; это имеет тот недостаток, что имеет значительные последствия для управления памятью, а именно, кому принадлежит указатель? и вам нужно создать объект в куче, который еще не существует в куче, чтобы сделать это?

Лучший вариант - взять указатель на структуру как параметр "out", использовать этот указатель для сохранения фактического результата, а затем вернуть int код состояния, указывающий на успех или неудачу (или bool, если вы есть компилятор C99). Это будет выглядеть примерно так:

int give_me_a_struct(MyStruct*);

MyStruct result;
if (give_me_a_struct(&result)) {
    //  yay!  we got a result!
}
else {
    //  boo!  we didn't get a result!
}

Если give_me_a_struct возвращает ноль, это означает, что он не нашел результат и объект result не был заполнен. Если он возвращает ненулевое значение, это означает, что он нашел результат и объект result был заполнен.

2 голосов
/ 07 ноября 2010

C не допускает глобальных неконстантных назначений.Так что вы должны сделать это в функции:

void init() {
   NotFoundStruct.x = 0;
   NotFoundStruct.y = 0;
}

Что касается сравнения, C не знает, как применить оператор == к структуре.Вы можете перегрузить (переопределить) оператор в C ++, но не в C.

Таким образом, чтобы увидеть, является ли возвращаемое значение пустым, вы можете выбрать

  1. Пусть каждая функция возвращаетлогическое значение, чтобы указать, найдено или нет, и вернуть значения структуры через указатели через список аргументов.(например. bool found = give_me_a_struct(some_input, &thing);)
  2. Возвращает указатель на структуру, которая может быть NULL, если ничего не существует.(например, MyStruct* thing = give_me_a_struct(some_input);)
  3. Добавьте в структуру дополнительное поле, которое указывает, является ли объект действительным.

Третий вариант является наиболее общим для других случаев, но требуетбольше данных для хранения.Лучшим вариантом для вашего конкретного вопроса является первый вариант.

1 голос
/ 07 ноября 2010
// MyStruct.h

typedef struct _MyStruct {
  // fields
} MyStruct;

extern MyStruct NotFoundStruct;

// MyStruct.c

#include "my_struct.h"
MyStruct NotFoundStruct = {0};

Но поскольку вы не можете использовать оператор ==, вам придется найти другой способ его различить. Один (не идеальный) способ - зарезервировать флаг bool для обозначения действительности. Таким образом, только это должно быть проверено, чтобы определить, является ли это действительным экземпляром.

Но я думаю, что вы должны рассмотреть предложенное Джеймсом решение вместо

0 голосов
/ 07 ноября 2010

В шапке:

// Structure definition then
extern MyStruct myStruct;

В .c, который содержит глобальные данные

struct MyStruct myStruct
{
   initialize field 1,
   initialize field 2,
   // etc...
};
...