2008-09-25 8 views
2

Je suis en train de refactoriser le module C "spaghetti code" pour travailler dans un environnement multitâche (RTOS).Refonte globale à locale. Devraient-ils être statiques ou non?

Maintenant, il existe des fonctions très longues et beaucoup de variables globales inutiles.

Lorsque j'essaie de remplacer des variables globales qui existent uniquement dans une fonction avec des locaux, je me retrouve dans un dilemme. Chaque variable globale se comporte comme "statique" locale - par ex. gardez sa valeur même si vous quittez et ré-entrez dans la fonction.

Pour le multitâche, les variables locales "statiques" sont les plus mauvaises du global. Ils rendent les fonctions non réentrées.

Il existe un moyen d'examiner si la fonction est relâchée sur la préservation de ré-encaissement de valeur variable sans suivre tout le flux logique?

Répondre

0

S'il vous plaît donner des exemples de ce que vous appelez les variables « globales » et « locales »

int global_c; // can be used by any other file with 'extern int global_c;' 

static int static_c; // cannot be seen or used outside of this file. 

int foo(...) 
{ 
    int local_c; // cannot be seen or used outside of this function. 
} 

Si vous fournissez des exemples de code de ce que vous avez et ce que vous avez changé, nous pourrions mieux répondre à la question.

8

Réponse courte: non, il n'y a aucun moyen de dire automatiquement si la fonction se comportera différemment selon que la déclaration d'une variable locale est statique ou non. Vous devez juste examiner la logique de chaque fonction qui utilise des globales dans le code original. Cependant, si le remplacement d'une variable globale par une variable statique de portée locale signifie que la fonction n'est pas réentrante, alors elle n'était pas réentrante lorsqu'elle était globale. Donc, je ne pense pas que le fait de changer une variable locale en variable statique locale rendra vos fonctions moins réentrantes qu'au départ.

A condition que le global ne soit réellement utilisé que dans cette portée (que le compilateur/éditeur de liens devrait confirmer lorsque vous supprimez le global), le comportement devrait être proche de la même. Il y a peut-être des problèmes quand les choses sont initialisées, je ne peux pas me rappeler ce que la norme dit: si l'initialisation statique se produit en C en même temps qu'en C++, quand l'exécution atteint la déclaration, alors vous pourriez avoir changé fonction concomitante dans une fonction non concurrentielle.

Déterminer si une fonction est sûre pour la ré-entrée nécessite également de regarder la logique. À moins que la norme ne dise le contraire (je n'ai pas vérifié), une fonction n'est pas automatiquement non-rentrante juste parce qu'elle déclare une variable statique. Mais si vous utilisez une méthode globale ou statique de manière significative, vous pouvez supposer qu'elle n'est pas réentrante. S'il n'y a pas de synchronisation, supposez qu'il est également sans danger pour la concurrence.

Enfin, bonne chance. Ce type de code est très éloigné de ce que vous voulez ...

+0

Il est plus facile de rendre le multitâche de variables globales conscient en le protégeant avec mutex, de traiter la variable statique de portée de procédure. – landmn

+0

Rien ne vous empêche de protéger une variable statique locale avec un mutex, comme vous l'avez fait avec la variable globale. En fait, si une variable globale a un mutex associé, vous devriez également déplacer ce mutex dans la portée. – mbyrne215

+0

Peut-être que c'est lié à la mise en œuvre, mais les mutex dans le RTOS avec lesquels je travaille sont toujours globaux. Par conséquent, rendre la variable protégée aussi globale est plus intuitif pour moi. – landmn

1

Si votre compilateur vous avertit si une variable est utilisée avant l'initialisation, indiquez une variable suspectée locale sans lui affecter de valeur dans sa déclaration.

Toute variable donnant un avertissement ne peut pas être rendue locale sans changer d'autre code.

+0

Vous pourriez avoir une fonction qui assigne toujours à la variable (évitant ainsi l'avertissement), mais lui renvoie un pointeur (signifiant ainsi qu'elle se cassera si la variable est rendue automatique). –

+0

Je réalise que cela ne contredit pas ce que vous avez dit, mais cela signifie que le test ne fonctionne que dans un sens: l'avertissement signifie que la variable est "mauvaise", mais "pas d'avertissement" ne signifie pas que c'est bon. –

0

Si je comprends bien votre question, votre préoccupation est que les variables globales conservent leur valeur d'un appel de fonction à l'autre. Évidemment, lorsque vous passez à l'utilisation d'une variable locale normale, ce ne sera pas le cas. Si vous voulez savoir si vous pouvez ou non les changer, je ne pense pas que vous ayez d'autre choix que de lire et de comprendre le code. Faire simplement une recherche en texte intégral pour le nom de la variable en question pourrait être instructif.

Si vous voulez une solution rapide et sale qui n'est pas complètement sûre, vous pouvez simplement la changer et voir quelles pauses. Je vous recommande de vous assurer d'avoir une version à laquelle vous pouvez revenir dans le contrôle de la source et de configurer des tests unitaires à l'avance.

1

La modification de variables globales en variables locales statiques aidera un peu, puisque les possibilités de modification ont été réduites. Cependant, le problème de la concurrence reste toujours un problème et vous devez contourner ce problème en verrouillant l'accès à ces variables statiques. Mais ce que vous voulez faire est de pousser la définition de la variable dans la portée la plus élevée qui est utilisée comme locale, puis passez-la comme argument à tout ce qui en a besoin. Cela nécessite évidemment beaucoup de travail (puisqu'il a un effet en cascade). Vous pouvez regrouper des variables de même type dans des objets "contextuels", puis les transmettre.

Voir le modèle de conception Encapsulate Context

1

Si vos vars globales sont vraiment utilisées que dans une fonction, que vous perdez rien en les rendant dans les locaux statiques car le fait qu'ils étaient mondiale fait la fonction de toute façon qui les a utilisés non-réentrant. Vous gagnez un peu en limitant la portée de la variable.

Vous devez apporter cette modification à toutes les variables globales utilisées dans une seule fonction, puis examiner chaque variable locale statique pour voir si elle peut être rendue non statique (automatique).

La règle est la suivante: si la variable est utilisée dans la fonction avant d'être définie, laissez-la statique.

Exemple d'une variable pouvant être rendue locale automatique (vous devez mettre "int nplus4;" à l'intérieur de la fonction (vous n'avez pas besoin de la mettre à zéro puisqu'elle est définie avant l'utilisation et cela devrait émettre un avertissement si vous l'utiliser avant de le mettre, une vérification utile).

int nplus4 = 0;   // used only in add5 
int add5 (int n) { 
    nplus4 = n + 4;  // set 
    return nplus4 + 1; // use 
} 

le nplus4 var est défini avant d'être utilisé Voici un exemple qui devrait être laissé statique en mettant « static int nextn = 0; » à l'intérieur de la fonction:

int nextn = 0;    // used only in getn 
int getn (void) { 
    int n = nextn++;  // use, then use, then set 
    return n; 
} 

Notez que cela peut être compliqué, "nextn++" n'est pas paramétré, c'est l'utilisation et le réglage car c'est équivalent à "nextn = nextn + 1". Autre chose à surveiller: dans un environnement RTOS, l'espace de la pile peut être plus limité que la mémoire globale, donc faites attention à déplacer les grandes variables globales telles que "char buffer[10000]" dans les fonctions.

Questions connexes