Pergunta

Atualmente estamos desenvolvendo um aplicativo para um MCU msp430 e estamos enfrentando alguns problemas estranhos.Descobrimos que declarar arrays dentro de um escopo após a declaração de variáveis ​​"normais", às vezes causa o que parece ser um comportamento indefinido.Assim:

foo(int a, int *b);

int main(void)
{
    int x = 2;
    int arr[5];

    foo(x, arr);

    return 0;
}

foo recebe um ponteiro como segunda variável, que às vezes não aponta para chegar variedade.Verificamos isso percorrendo uma única etapa do programa e vemos que o valor da variável de array como ponteiro arr no escopo principal não é o mesmo que o valor da variável de ponteiro b no escopo foo.E não, isso não é realmente reproduzível, apenas observamos esse comportamento de vez em quando.

Isso é observável mesmo antes de uma única linha da função foo ser executada, o parâmetro do ponteiro passado (b) simplesmente não está apontando para o endereço que arr está.

Mudar o exemplo parece resolver o problema, assim:

foo(int a, int *b);

int main(void)
{
    int arr[5];
    int x = 2;

    foo(x, arr);

    return 0;
}

Alguém tem alguma opinião ou sugestão sobre por que experimentamos esse comportamento?Ou experiências semelhantes?O guia de programação MSP430 especifica que o código deve estar em conformidade com as especificações ANSI C89.e então eu queria saber se diz que os arrays devem ser declarados antes das variáveis ​​​​não-array?

Qualquer contribuição sobre isso seria apreciada.


Atualizar

@Adam Shiemke e tomlogic:

Estou me perguntando o que o C89 especifica sobre as diferentes maneiras de inicializar valores nas declarações.Você tem permissão para escrever algo como:

int bar(void)
{
    int x = 2;
    int y;

    foo(x);
}

E se sim, que tal:

int bar(int z)
{
    int x = z;
    int y;

    foo(x);
}

Isso é permitido?Presumo que o seguinte deve ser ilegal C89:

int bar(void)
{
    int x = baz();
    int y;

    foo(x);
}

Desde já, obrigado.


Atualização 2Problema resolvido.Basicamente desabilitamos interrupções antes de chamar a função (foo) e após declarações de variáveis.Conseguimos reproduzir o problema em um exemplo simples, e a solução parece ser adicionar uma instrução _NOP() após a chamada de interrupção de desativação.

Se alguém estiver interessado posso postar o exemplo completo reproduzindo o problema, e a correção?

Obrigado por todas as contribuições sobre isso.

Foi útil?

Solução

Você deve ser capaz de determinar se é um bug do compilador com base no código assembly produzido.A montagem fica diferente quando você altera a ordem das declarações das variáveis?Se o seu depurador permitir, tente percorrer a montagem em uma única etapa.

Se você encontrar um bug no compilador, verifique também sua otimização.Já vi bugs como esse introduzidos pelo otimizador.

Outras dicas

Isso parece um bug do compilador.

Se você usar seu primeiro exemplo (o problemático) e escrever sua chamada de função como foo(x, &arr[0]);, você vê os mesmos resultados?E se você inicializar o array como int arr[5] = {0};?Nenhum deles deve mudar nada, mas se mudarem, isso indicará um bug do compilador.

Na sua pergunta atualizada:

Basicamente, desativamos as interrupções antes de chamar a função (foo) e após declarações de variáveis.Conseguimos reproduzir o problema em um exemplo simples, e a solução parece ser adicionar um _NOP() instrução após a chamada de interrupção de desabilitação.

Parece que a interrupção que desabilita intrínseca/função/macro (ou como as interrupções estão desabilitadas) pode estar fazendo com que uma instrução seja 'ignorada' ou algo assim.Eu investigaria se está codificado/funcionando corretamente.

Ambos os exemplos parecem estar em conformidade com C89 para mim.Não deve haver nenhuma diferença observável no comportamento, assumindo que foo não está acessando além dos limites da matriz.

Para C89, as variáveis ​​precisam ser declaradas em uma lista no início do escopo antes de qualquer atribuição.C99 permite misturar atribuição e declaração.Então:

{ 
    int x; 
    int arr[5];

    x=5;
...

é o estilo c89 legal.Estou surpreso que seu compilador não tenha gerado algum tipo de erro se não suportar c99.

Supondo que o código real seja muito mais complexo, aqui estão algumas coisas que eu verificaria, lembre-se de que são suposições:

Você poderia estar transbordando a pilha de vez em quando?Se sim, isso poderia ser algum artefato de "defesa de pilha" do compilador/uC?O valor incorreto de &foo está dentro de um intervalo de memória previsível?em caso afirmativo, esse intervalo tem algum significado (dentro da pilha, etc.)?

O mcu430 possui intervalos diferentes para endereçamento de RAM e ROM?Ou seja, o espaço de endereço da memória RAM é de 16 bits enquanto o espaço de endereço do programa é de 24 bits?Os PICs possuem essa arquitetura, por exemplo.Nesse caso, seria viável que arr estivesse sendo alocado como rom (24 bits) e a função esperasse um ponteiro para ram (16 bits). O código funcionaria quando o arr fosse alocado nos primeiros 16 bits do espaço de endereço, mas tijolo se estivesse acima desse intervalo .

Talvez você tenha em algum lugar do seu programa uma gravação ilegal na memória que corrompa sua pilha.

Você deu uma olhada na desmontagem?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top