ошибка: X может использоваться неинициализированным в этой функции в C - PullRequest
1 голос
/ 10 марта 2009

Я получаю эту ошибку

error: Access.Core may be used uninitialized in this function

А это мой код:

 static int FirstTime = 1;
 MyStruct Access;

 if (FirstTime) {
   FirstTime = 0;
   Access = Implementation();
   DoSomething(Access);
 }

 if(Other_Variable) {
    Access = Implementation2();
    DoSomething(Access);
  }

  //The Other_Variable will be set to 1 and to 0 by other part of the code

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

Если я делаю Access статичным, но мне не нравится делать его статичным, потому что при любом другом вызове Access будет обновляться. Есть ли способ избежать проблемы, не делая ее статичной?

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

Ответы [ 4 ]

6 голосов
/ 10 марта 2009

Сделайте Access таким (и удалите FirstTime и if):

static MyStruct Access = Implementation(this_b);

Причина, по которой вы получаете это предупреждение, состоит в том, что статические переменные переживают один вызов функции. Их значение сохраняется во всех вызовах функций ( без в зависимости от того, какой поток вызывает эту функцию). Таким образом, FirstTime будет контролировать инициализацию Access. При первом вызове функции, в которой находится код, будет правильно инициализирована переменная Access. Но при каждом последующем вызове функции FirstTime равен нулю, и вы не больше не инициализируете Access и, следовательно, будете использовать неинициализированную переменную в коде.

Редактировать: Теперь, с вашей обновленной информацией, вы говорите, что у вас есть две Implementation функции. Первый раз, когда вы хотите использовать одну, а все остальные раз вы хотите использовать другую функцию. Как насчет этого тогда:

 // static will be false/zero by default
 static bool AlreadyCalled;
 MyStruct Access;

 if (!AlreadyCalled) {
   Access = Implementation();
   AlreadyCalled = true;
 } else {
   Access = Implementation2();
 }

В зависимости от вашего фактического варианта использования, однако, могут быть лучшие способы справиться с этим. Например, почему бы не обновить состояние Access, например:

// let the default constructor initialize it
// to a plausible state
static MyStruct Access;

// use RAII to update the state of Access when this
// function returns. 
MyUpdater updater(Access);

// now, do whatever the function does. 

Примерно так: MyUpdater:

struct MyUpdater {
    MyStruct &s;
    MyUpdater(MyStruct &s):s(s) { }
    ~MyUpdater() {
        s.ChangeState();
    }
};

Этот шаблон называется RAII: вы связываете некоторые полезные действия с конструктором и деструктором локально размещенного объекта.

2 голосов
/ 10 марта 2009

@ Литб ответ интересный. Эквивалентная программа следует. Код компилируется и работает, как указано в C ++, но не компилируется в C.

#include <stdio.h>

static int newval(void) { return 3; }

void inc(void)
{
    static int a = newval();

    a++;
    printf("%d\n", a);
}

int main(void)
{
    int i;
    for (i = 0; i < 10; i++)
        inc();
    return(0);
}

gcc говорит:

x.c: в функции 'inc': x.c: 7: ошибка: элемент инициализатора не является константой

g ++ вполне доволен этим.

Это разница между C и C ++, о которой я не знал (но это не вписалось бы в 300 символов, поэтому я не могу легко сделать это комментарием).


@ Эдуардо задал один из вопросов в комментариях: «Почему C не позволяет этого, а C ++ это позволяет?». Поскольку ответ более 300 символов ...

Как сказал @litb в комментариях, в C вы можете использовать константы только для инициализаторов статических переменных. Это отчасти потому, что значения устанавливаются перед вызовом main (), и пользовательские функции не вызываются до вызова main (). В отличие от этого, C ++ позволяет инициализировать (определяемые пользователем) конструкторы глобальных и статических переменных перед вызовом main (), поэтому нет причин не разрешать вызывать и другие пользовательские функции, поэтому инициализация является разумной. С C89 вы ограничены в инициализаторах, которые вы можете использовать с автоматическими (локальными) переменными; в C99 вы можете использовать практически любое выражение для инициализации любой локальной переменной.

1 голос
/ 10 марта 2009

Access не является статичным, поэтому его необходимо создавать при каждом вызове.

Попробуйте упростить код до чего-то вроде:

static MyStruct Access = Implementation(this_b);

Это гарантирует, что функция будет вызываться только при первом запуске метода и что Access будет хранить значение между вызовами.

1 голос
/ 10 марта 2009

Доступ не является статическим, поэтому каждый раз, когда вызывается функция, создается новый экземпляр. Только в первый раз вы фактически назначаете ему какое-либо значение; это значение теряется при выходе из функции.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...