Глобальная структура в c (элемент инициализатора не является константой времени компиляции)

Я довольно новичок в C, и у меня есть некоторые проблемы.

У меня есть следующее определение структуры:

struct env {
  struct env *next;
  char varName[8];
  int n;
};

Я хочу создать несколько таких структур в некоторых из моих функций, поэтому я создал функцию для этого:

struct env *mkEnv(char c[8] , int value , struct env *toadd){
    struct env *enviroment = malloc(sizeof(struct env));
    enviroment->n = value;
    enviroment->next = toadd;
    strcpy(enviroment->varName , c);
    return enviroment;
}

Я хочу создать подобную структуру глобально, которая является постоянной с некоторыми постоянными значениями и изначально имеет указатель на следующую структуру NULL.

Итак, я сделал что-то вроде этого:

    //not in a function
    struct env *list = mkEnv("pot" , 0 , NULL);

    //Beginning of a function
    int eval(struct expression *exp){
        ... // code here that might add a new structure to the pointer of list
    }

Однако я получаю следующую ошибку:

evalexp.c:116:20: ошибка: элемент инициализатора не является константой времени компиляции struct env *list = mkEnv("p", 0, NULL);

Я понимаю, что означает эта ошибка, после поиска сообщения об ошибке, но есть ли способ создать структуру где-то вне функции, не получая этой ошибки компиляции?

Чтобы было понятнее: я хочу создать структуру, как определено выше (как если бы это был заголовок списка). так что все мои функции могут получить доступ и добавить к нему материал. Это разбор его как списка и/или добавление новых элементов в этот список.

Заранее спасибо!


person Jetmax    schedule 21.02.2016    source источник


Ответы (3)


Функция не может быть вызвана в файловой области.

Вы должны использовать постоянные значения и определить фактическую переменную структуры:

struct env lists = { NULL , "pot" , 0 };
struct env *list = &lists;

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

person 2501    schedule 21.02.2016
comment
Спасибо ! Я выбрал ваш ответ, потому что он был более конкретным для моей проблемы! Хотя остальные тоже были правы! - person Jetmax; 21.02.2016
comment
Лучше использовать назначенные инициализаторы. Это менее подвержено ошибкам при изменении struct (обратите внимание, что определение типа часто не находится непосредственно рядом с определением переменной). - person too honest for this site; 21.02.2016

Определите переменную и инициализируйте ее в main.

struct env *list;

int main() {
    list = mkEnv("pot" , 0 , NULL);
    ....
}

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

person Joni    schedule 21.02.2016

Вы можете использовать следующий синтаксис:

struct env
{
  struct env *next;
  char varName[8];
  int n;
};
struct env *list = &((struct env){ NULL, "pot" , 0});

Обратите внимание на приведение к структуре, примененное к инициализатору, и addess of оператор &, примененный к нему ;-)
Подробно о части: (struct env){ NULL, "pot" , 0} сообщает компилятору, что инициализатор { NULL, "pot" , 0} ссылается на структуру struct env, это инструктирует компилятор создать инициализированный экземпляр struct env. Затем мы получаем адрес этой структуры с помощью оператора & и присваиваем его указателю list.
Работает с компиляторами C99 и C11.

person Frankie_C    schedule 21.02.2016