Question

Je travaille sur un projet sur un 8051 où chaque nombre d'octets. En tant que tel, j'utilise des variables globales où je normalement pas. La méthode normale de pointeurs passant dans une fonction ajoute trop de frais généraux ici.

I ai un certain nombre de fonctions qui utilisent un seul variables de bits (une extension spécifique du compilateur C ) pour signaler le résultat d'une fonction en plus de la valeur de retour normale.

bit global_error_flag = 0;
bit global_data_ready_flag = 0;

unsigned char A_Function (void) {
    // Do some stuff

    if ( badness ) {
        global_error_flag = 0;
        global_data_ready_flag = 1;

        return 0;
    }

    if ( data_is_ready_use ) {
        global_data_ready_flag = 1;
    }

    return a_value;    
}

void Other_Function (void) {
    unsigned char c;

    c = A_Function();

    if( global_error_flag) {
        // Do error stuff here.
    }
    else
    if( global_data_ready_flag ) {
        // Do data processing here.
    }
    global_error_flag = 0;
    global_data_ready_flag = 0;

}

Étant donné que la technique est mal, est-il une manière que je peux rendre le code plus lisible?

La meilleure façon dois-je indiquer que les appels de fonction aura l'effet secondaire de la définition de ces drapeaux? assez des commentaires? Dois-je nommer les fonctions pour indiquer leur API (style quasi-hongrois)? Dois-je utiliser une macro pour marquer ces appels:

#define FUNCTION_SETS_FLAGS(code) (code)

FUNCTION_SETS_FLAGS( c = A_Function() );

D'autres idées?

Était-ce utile?

La solution

Vos globals sont marqués pour plus de clarté, c'est un bon point de départ.

Idéalement, vous voulez quelque chose qui ne compilera pas si vous vous trompez. Cela signifie que les macros et les commentaires ne fonctionneront pas.

Je tiens à une convention de nommage pour les fonctions - pas nécessairement hongrois, mais quelque chose comme A_Function_Returns_Flags, ou moins bavard si vous pouvez penser que

.

Autres conseils

En utilisant une convention, si vous voulez l'appeler « hongrois » ou non, est la meilleure façon que je peux penser à marquer cette désinvolture. Stylistiquement, une sorte de préfixe de dénomination serait préférable à la #define vide, au moins pour moi.

Ceci est en fait assez commun, je pense. Je sais que l'environnement de programmation S60 utilise beaucoup de marques conventionnelles sur les fonctions pour indiquer qu'ils jettent des exceptions, par exemple.

Je l'ai fait mon doctorat sur une question similaire en Java. Je peux vous dire une chose que vous ne devriez pas faire: ne comptez pas sur la documentation parce que vous dépendez quelqu'un qui lit réellement. Vous devez ajouter un peu de soupçon dans le nom de la méthode pour indiquer que l'utilisateur doit lire les documents pour en apprendre davantage sur les effets secondaires. Si vous choisissez quelque chose et que vous êtes en accord avec elle, vous vous tenez sans doute le plus de chance.

Si vous voulez juste mentionner qu'une fonction affecte variable globale (s), puis un préfixe simple (hongrois) peut aider.

Mais si vous voulez parler de tous les fanions de (s) qu'il touche, puis, en utilisant l'en-tête de la fonction est probablement la voie à suivre. Comme par exemple,

  /*************************************************************************
     * FUNCTION    : <function_name>
     * DESCRIPTION : <function description> 
     * PARAMETERS  : 
     *  Param1  - <Parameter-1 explanation>
     *  Param2  - <Parameter-2 explanation>
     *  Param3  - <Parameter-3 explanation>
     * RETURN      : <Return value and type>
     * GLOBAL VARIABLES USED: 
     *  Global1 - <Global-1 explanation>
     *  Global2 - <Global-2 explanation>
     *  Global3 - <Global-3 explanation> 
  *************************************************************************/

Cela ne veut pas vraiment vous aider, mais GCC a une façon de faire le en face de ce que vous voulez: pour marquer les fonctions qui ont pas effets secondaires. Voir la const pure . Ceci est plus pour l'optimisation de la documentation, la pensée: si le compilateur sait qu'une fonction donnée ne porte pas sur des données autres que ses arguments, il peut effectuer des optimisations plus intelligentes telles que mouvement de code invariant de boucle .

Vous pouvez utiliser une macro pour simuler la fonction d'avoir plusieurs paramètres:


unsigned char _a_function(void);

#define A_Function(ret_val) (*(ret_val) = _a_function(), !global_error_flag)

...
unsigned char var;
/* call the function */
if (!A_Function(&var))
{
    /* error! */
}
else
{
    /* use var */
    var++;
}

Je ne l'ai pas essayé de le compiler, ne peut donc pas dire que cela va fonctionner, mais je pense qu'il devrait.

D'abord, je voudrais essayer de le code d'une manière qu'il n'y a qu'un seul producteur et un seul consommateur pour chacun de ces drapeaux. Ensuite, je clair / mettre un drapeau uniquement en cas de besoin. Comme pour indiquer l'effet secondaire, un en-tête standard sur le dessus de la fonction, le style Doxygen, devrait être suffisant:

    // Function func
    // Does something
    // Consumes ready_flag and  sets error_flag on error.

    int func()
    {
        if (ready_flag)
        {
            //do something then clear the flag
            if (some_error)
                error_flag = x;
            ready_flag = 0;
        }
        //don't mess with the flags outside of their 'scope'
        return 0;
    }

D'autre part, si l'erreur et des drapeaux prêts sont que vous pourriez mutuellement exclusives, utilisez un octet (ou les bits dans un octet / registre) pour indiquer la préparation ou un état d'erreur.

0 pour une erreur, une pour non prêt / sans erreur et 2 pour préparer / sans erreur (ou -1, 0, 1, peu importe)

IIRC, le jeu d'instructions standard 8051 ne fonctionne pas sur les bits simples, donc en utilisant un octet entier pour (divers) drapeaux ne devraient pas vous donner un énorme coup de performance.

Si vous ne l'avez pas déjà fait, vous pouvez également consulter la sdcc sur sourceforge , il est un compilateur C spécifiquement destiné à être utilisé pour le développement intégré qui vise aussi le 8051, en plus le compilateur prend en charge un certain nombre de coutume, compilateur spécifiques à la cible et non standard intrinsics pour divers cas d'utilisation, aussi j'ai personnellement trouvé le développement l'équipe d'être très ouvert et réactif des idées pour de nouvelles améliorations et d'autres demandes de fonctionnalités connexes.

Si vous avez vraiment tenir à ces variables globales, vous pouvez le rendre évident qu'une fonction peut les modifier en attendant les références à eux comme arguments de la fonction:

unsigned char A_Function (bit *p_error_flag, bit *p_data_ready_flag)
{
  ...
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top