Question

Nous développons actuellement une application pour un microcontrôleur MSP430, et courons quelques problèmes étranges. Nous avons découvert que la déclaration de tableaux withing un champ après la déclaration des variables « normales », provoque parfois ce qui semble être un comportement non défini. Comme ceci:

foo(int a, int *b);

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

    foo(x, arr);

    return 0;
}

foo est passé un pointeur comme la deuxième variable, que parfois ne pointe pas vers le arr array. Nous vérifierons cela en mode pas à pas à travers le programme, et voir que la valeur de la variable arr tableau-as-a-pointeur dans le champ d'application principal est pas la même que la valeur de la variable de pointeur b dans le champ d'application de foo. Et non, ce n'est pas vraiment reproductible, nous venons d'observer ce comportement une fois dans un certain temps.

Ceci est observable avant même une seule ligne de la fonction foo est exécutée, le paramètre de pointeur transmis (b) est tout simplement pas pointant vers l'adresse qui est arr.

Modification de l'exemple semble résoudre le problème, comme ceci:

foo(int a, int *b);

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

    foo(x, arr);

    return 0;
}

Quelqu'un at-il une entrée ou des notes pour lesquelles nous faisons l'expérience de ce comportement? Ou des expériences similaires? Le guide de programmation MSP430 précise que le code doit être conforme à la spécification ANSI C89. et je me demandais s'il est dit que les tableaux doivent être déclarées avant les variables non-tableau?

Toute entrée sur ce serait apprécié.

Mise à jour

@Adam Shiemke et tomlogic:

Je me demande ce que C89 précise sur les différentes façons d'initialiser les valeurs dans les déclarations. Êtes-vous autorisé à écrire quelque chose comme:

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

    foo(x);
}

Et si oui, qu'en est:

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

    foo(x);
}

Est-ce permis? Je suppose que les conditions suivantes doivent être C89 illégale:

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

    foo(x);
}

Merci d'avance.

Mise à jour 2 Problème résolu. Fondamentalement, nous où la désactivation des interruptions avant d'appeler la fonction (foo) et après les déclarations de variables. Nous où en mesure de reproduire le problème dans un exemple simple, et la solution semble être d'ajouter une déclaration _NOP () après la désactivation de l'appel d'interruption.

Si quelqu'un est intéressé, je peux poster l'exemple complet reproduisant le problème et la solution?

Merci pour tous les commentaires sur ce sujet.

Était-ce utile?

La solution

Vous devriez être en mesure de déterminer si elle est un bug du compilateur basé sur le code de montage qui est produit. L'assemblage différent lorsque vous modifiez l'ordre des déclarations de variables? Si votre débogueur vous permet, essayez le pas à pas à travers l'ensemble.

Si vous trouvez un bug du compilateur, aussi, vérifiez votre optimisation. J'ai vu des bugs comme celui-ci introduit par l'optimiseur.

Autres conseils

Cela ressemble à un bug du compilateur.

Si vous utilisez votre premier exemple (la problématique) et d'écrire votre appel de fonction comme foo(x, &arr[0]);, voyez-vous les mêmes résultats? Qu'en est-il si vous initialisez le tableau comme int arr[5] = {0};? Aucun de ceux-ci devraient changer quoi que ce soit, mais s'ils le font évoquerait un bug du compilateur.

Dans votre question mise à jour:

  

En fait, nous où la désactivation des interruptions avant d'appeler la fonction (foo) et après les déclarations de variables. Nous où en mesure de reproduire le problème dans un exemple simple, et la solution semble être d'ajouter une déclaration de _NOP() après la désactivation de l'appel d'interruption.

Il semble que l'interruption désactivation intrinsèque / fonction / macro (ou cependant les interruptions sont désactivées) peut causer une instruction à « sautée » ou quelque chose. Je tentent de déterminer s'il est codé / fonctionne correctement.

Les deux exemples semblent être conformes C89 pour moi. Il devrait y avoir aucune différence observable dans le comportement en supposant que foo n'accède pas à au-delà des limites du tableau.

Pour C89, les variables doivent être déclarées dans une liste au début de la portée avant toute cession. C99 vous permet de mélanger la cession d'une déclaration. Donc:

{ 
    int x; 
    int arr[5];

    x=5;
...

est de style c89 juridique. Je suis surpris que votre compilateur n'a pas jeté une sorte d'erreur que si elle ne prend pas en charge C99.

En supposant que le code réel est beaucoup plus complexe, voici quelques choses que je vérifieraient, garder à l'esprit qu'ils sont des suppositions:

Pourriez-vous déborderont la pile à l'occasion? Dans ce cas cela pourrait être un artefact de la « défense de la pile » par le compilateur / uC? Est-ce que la valeur incorrecte de & chute foo dans une plage de mémoire prévisible? si cette plage ne possède donc une signification (à l'intérieur de la pile, etc.)?

Est-ce que mcu430 ont des gammes différentes pour faire face RAM et ROM? Ce qui est, est l'espace d'adressage pour 16bit ram tandis que l'adresse du programme 24bit de l'espace? PIC ont une telle architecture par exemple. Dans ce cas, il serait possible que arr est se réparti comme rom (24bit) et la fonction attend un pointeur vers la RAM (16 bits) le code fonctionnerait lorsque l'arr a été attribué dans la première 16bit de l'espace d'adressage mais brique si son au-dessus de cette gamme .

Peut-être que vous avez à un certain endroit dans votre programme en écriture de la mémoire illégale qui corrompt votre pile.

Avez-vous un regard sur le démontage?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top