erro: X pode ser usada sem ser inicializada nesta função em C
-
06-07-2019 - |
Pergunta
Estou recebendo este erro
error: Access.Core may be used uninitialized in this function
E este é meu código:
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
Meu código é assim porque eu quero chamar para a função Implementação apenas na primeira vez. Em cada chamada a variável de acesso vai ser atualizado para que ele não fazer muitos sentido make-lo estático.
Se eu fizer obras estáticas de acesso, mas eu não gosto de fazer isso estática, porque em todas as outras chamadas de acesso vai ser atualizado. Qualquer forma de evitar o problema sem torná-lo estático?.
Além disso, quaisquer opções melhores para executar apenas uma vez uma função em vez de usar uma variável estática são bem-vindos.
Solução
Faça Access
como este (e FirstTime
remove eo if
):
static MyStruct Access = Implementation(this_b);
A razão que você receber este aviso é porque variáveis ??estáticas sobreviver uma chamada de função. Seu valor é mantido em todas as chamadas de função ( sem relação aos quais chamadas de rosca que de função). Então, FirstTime
irá controlar se você inicializa Access
. A primeira vez que você chamar a função que o código é em vão inicializar corretamente a variável Access
. Mas com cada novo convite função, FirstTime
é zero, e você não initialize Access
mais, e, portanto, vai usar uma variável não inicializada para baixo o código.
Editar: Agora, com as informações atualizadas, você diz que você tem duas funções Implementation
. A primeira vez que você quiser usar um, e todas as outras vezes que você deseja usar outra função. Como sobre isso, então:
// static will be false/zero by default
static bool AlreadyCalled;
MyStruct Access;
if (!AlreadyCalled) {
Access = Implementation();
AlreadyCalled = true;
} else {
Access = Implementation2();
}
Dependendo do seu caso de uso real, pode haver melhores maneiras de lidar com isso, porém. Por exemplo, por que não atualizar o estado de Access
, como este:
// 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.
Algo como isto para MyUpdater
:
struct MyUpdater {
MyStruct &s;
MyUpdater(MyStruct &s):s(s) { }
~MyUpdater() {
s.ChangeState();
}
};
Esse padrão é chamado RAII
: Você associa alguma ação útil com o construtor e destruidor de um objeto alocado localmente.
Outras dicas
de @ litb é interessante. Um programa equivalente segue. As compilações de código e obras conforme indicado em C ++, mas não compilar em 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 diz:
x.c: Em função 'inc': x.c: 7: Erro: initializer elemento não é constante
g ++ está muito feliz com ele.
Essa é uma diferença entre C e C ++ que eu não estava ciente de (mas isso não iria caber em 300 caracteres, então não posso torná-lo um comentário, facilmente).
@Eduardo perguntou uma das perguntas nos comentários: "Por que C não permite isso e C ++ permite isso?". Como a resposta é mais do que 300 caracteres ...
Como @ litb disse nos comentários, em C você só pode usar constantes para inicializadores de variáveis ??estáticas. Isto é em parte porque os valores são definidos antes principal () é chamado, e não há funções definidas pelo utilizador são chamados antes principal () é chamado. C ++, por outro lado, permite que as variáveis ??globais e estáticos para ser inicializado por construtores (definido pelo usuário) antes de main () é chamado, então não há nenhuma razão para não permitir que outras funções definidas pelo usuário para ser chamado também, para que a inicialização é razoável. Com C89, você está limitado nas initializers você pode usar com variáveis ??automáticas (locais); em C99, você pode usar praticamente qualquer expressão para inicializar qualquer variável local.
O acesso não é estática, toda vez que, portanto, uma nova instância é criada a função é chamada. Só no primeiro tempo através de você realmente atribuir qualquer valor a ela; este valor é perdido assim que a função sai.
Se você precisa de acesso a persistir entre as chamadas para a função, torná-lo estático.
Access
não é estática e, portanto, ele deve ser criado em cada chamada.
Considere simplificando o código para algo como:
static MyStruct Access = Implementation(this_b);
Isso garante que a função só serão chamados pela primeira vez o método é executado e que Access
vai conter o valor entre chamadas.