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

StackOverflow https://stackoverflow.com/questions/628410

  •  06-07-2019
  •  | 
  •  

Вопрос

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

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 будет обновляться. Есть ли способ избежать проблемы, не делая ее статичной?

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

Это было полезно?

Решение

Сделайте Access следующим образом (и удалите FirstTime и if ):

static MyStruct Access = Implementation(this_b);

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

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

 // 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 : вы связываете некоторые полезные действия с конструктором и деструктором локально размещенного объекта.

Другие советы

@ Литб ответ интересный. Эквивалентная программа следует. Код компилируется и работает так, как указано в 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 символов, поэтому я не могу легко сделать это комментарием).

<Ч>

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

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

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

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

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

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

static MyStruct Access = Implementation(this_b);

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top