2010-03-22 16 views
79

Y a-t-il des principes de conception connus, des meilleures pratiques et des modèles de conception que l'on peut suivre lors de la conception d'un projet C? Ou des principes de conception utiles pour la programmation procédurale (impérative) en général?Principes de conception, meilleures pratiques et modèles de conception pour C (ou programmation procédurale en général)?

(je suis enfant de la « génération orientée objet » et doivent concevoir un grand projet C pour la première fois)

+1

Vous pouvez être intéressé par les réponses à cette question: http://stackoverflow.com/questions/661307/recommendations-for-structuring-complex-applications-in-c – mouviciel

+0

En effet, merci beaucoup, mouviciel. – Dimi

+7

J'ai fait quelques recherches sur Internet et les bibliothèques universitaires, avant de poster ma question, et je n'étais pas débordé de livres sur la conception de logiciels pour C. Je vous demande votre préféré (ne parle pas de livres généraux, ne parle pas de conventions de codage noms de variables, mais sur une abstraction plus élevée, niveau d'architecture logicielle). De plus, je ne suis pas d'accord avec votre reproche de «compter sur les autres». Vous voulez dire que chaque programmeur devrait découvrir par lui-même les meilleures pratiques et les bons modèles de conception? C'est à coup sûr une question sur laquelle l'expérience des autres doit être utilisée. – Dimi

Répondre

56

cacher l'information - comme embrassée par Parnas (Software Fundamentals).

Une gestion prudente des en-têtes et la visibilité:

  • Tout dans un fichier source qui peut être caché du monde extérieur devrait être; seule l'interface externe documentée doit être exposée. Tout ce qui est exposé est déclaré dans un en-tête.
  • Cet en-tête est utilisé lorsque la fonctionnalité est nécessaire (et où elle est définie).
  • L'en-tête est autonome - quand vous en avez besoin, vous l'utilisez, et vous n'avez pas à vous inquiéter de 'ce que d'autres en-têtes dois-je inclure' car l'en-tête fonctionne en incluant tout ce dont il a besoin pour le faire fonctionner.
  • L'en-tête est auto-protégé - cela n'a donc aucune importance s'il est inclus plusieurs fois.

    #ifndef HEADER_H_INCLUDED 
    #define HEADER_H_INCLUDED 
    ...rest of header contents, including other #include lines if necessary 
    #endif /* HEADER_H_INCLUDED */ 
    
  • ensembles de conception de fonctions pour travailler sur des « objets » (généralement des structures) - et d'utiliser ces fonctions plutôt que de fouiller les entrailles de la structure du code qui l'utilise. Pensez-y comme une encapsulation auto-imposée.

+0

Bon point, merci, Jonathan. Les types de données abstraits sont un autre bon exemple d'informations se cachant avec une séparation nette de l'utilisation et de la mise en œuvre (interface externe connue et implémentation interne inconnue). – Dimi

20

Il y a un bon, libre, livre en ligne, intitulé Object-Oriented Programming With ANSI-C, qui couvre le thème de l'écriture de code orienté objet dans C. google search pour « orienté objet C » donne également un certain nombre d'autres bons exemples et ressources.

Si votre projet est critique pour la sécurité, MISRA-C est un bon ensemble de règles. Il est principalement destiné à c intégré, mais il peut également être utile dans d'autres domaines. Je me considère comme un codeur OO, et je fais beaucoup de travail avec Embed-C. Le meilleur conseil que je puisse donner, surtout pour les grands projets, est de ne pas trop en faire. Créer un framework OO complet au-dessus de C ANSI peut être très tentant, mais il faut beaucoup de temps et d'efforts pour bien faire les choses. Plus vous achetez, plus vous passerez de temps à déboguer votre framework au lieu de travailler sur le projet real. Approchez-vous de la tâche avec une tête claire et une bonne compréhension de YAGNI. Bonne chance!

+0

Merci, e.James. Je ne veux pas créer un cadre orienté objet au-dessus de ANSI C, mais rechercher des principes de conception de programmation procédurale spéciaux et appropriés. L'indice MISRA-C est très utile, surtout parce qu'il s'agit en fait d'un projet intégré. Je vais regarder de plus près. – Dimi

+0

Ah, les joies de l'embarqué C. N'oubliez pas que vous devez déclarer vos variables en haut de votre fonction (ou en haut de n'importe quel bloc {}}. Celui-là me mord toujours une ou deux fois ':)' –

6

La POO est une méthodologie et non une technologie. Donc, mon premier conseil est d'arrêter de penser à la programmation procédurale.

Pour le point de vue de James, vous ne voulez pas essayer de recréer un langage orienté objet ou prétendre que vous avez les capacités de celui-ci. Vous pouvez toujours faire toutes les bonnes choses en vous cramponnant à quelques principes simples:

  1. Testez tout.
  2. Trouvez ce qui varie et encapsulez-le.
  3. Conception d'interfaces.
19

Mes trois conseils:

  • tests unitaires en écriture. Ils vous aideront à vous concentrer sur un design qui résout votre problème au fur et à mesure. Bien mieux que de se fier (uniquement) à la pensée préméditée. Avoir un détecteur de fuite de mémoire (il y a toutes sortes de bibliothèques là-bas) installé et en cours d'exécution dès le premier jour. Avoir cette bibliothèque imprimer toutes les fuites dès que le programme/tests se termine. Cela vous permettra d'attraper une fuite dès que vous l'introduisez, rendant ainsi sa fixation beaucoup moins douloureuse. Ecrire le code OOP en C. Pas si difficile. Bien qu'il soit possible d'émuler la méthode de substitution, je suggère que vous commenciez par émuler des objets simples. Même ce mécanisme simple peut vous donner un grand kilométrage.

Voici un exemple:

struct Vector { 
    int size; 
    int limit; 
    int* ints; 
} 

Vector* Vector_new() { 
    Vector* res = (Vector*) malloc(sizeof(Vector)); 
    res->limit = 10; 
    res->size = 0; 
    res->ints = (int*) malloc(sizeof(int) * res.limit); 

    return res; 
} 


void Vector_destroy(Vector* v) { 
    free(v->ints); 
    free(v); 
} 

void Vector_add(Vector* v, int n) { 
    if(v->size == v->limit) { 
    v->limit = v->limit * 2 + 10; 
    v->ints = realloc(v->ints, v->limit);  
    } 

    v->ints[v->size] = n; 
    ++v->size; 
} 

int Vector_get(Vector* v, int index) { 
    if(index >= 0 && index < v->size) 
    return v->ints[index]; 

    assert false; 
} 
+0

Merci, Itay. Je vais suivre vos conseils. – Dimi

+0

Grand exemple simple. ('< v-> size()' dans 'Vector_get' devrait être sans'() 'je suppose?) – Carl

+0

@Carl - Merci, corrigé. –