2009-09-25 8 views
3

Je connais des langages de plus haut niveau, tous basés sur le web (PHP, javascript, un peu de python). J'ai finalement décidé d'apprendre une langue de niveau inférieur, et j'ai décidé d'aller avec C. Le problème est que toutes les langues que j'utilise sont fortement basées sur la POO. Vu que (basé sur la recherche que j'ai faite) C n'a pas de classes ou d'héritage. En conséquence, je vous demande ceci: Comment dois-je organiser mon code en C de manière organisée comme OOP, sans avoir à changer de langue ou juste avoir des fichiers avec des quantités infinies de fonctions?Style d'organisation de code pour C?

Éditer à partir de Future: Cette question est assez bête en y repensant. J'avais 15 ans et je n'avais pas de CS dans mon école ...

+1

cela dépend entièrement du problème que vous résolvez – dharga

+0

Pourriez-vous donner quelques exemples? – Backus

+0

Il ne recherche pas terriblement bien, mais cela a été répondu sur Stack Overflow à plusieurs reprises. Des liens quand j'y arrive. – dmckee

Répondre

16

C n'offre pas beaucoup d'organisation de code. Il y a des fonctions et des fichiers. Chaque fois que vous voulez implémenter une interface avec une implémentation cachée, ou peut-être avec des fonctions privées, créez deux fichiers, comme "foo.h" et "foo.c".

L'interface et/ou les fonctions publiques sont des prototypes de fonctions dans "foo.h", et les fonctions sont écrites dans "foo.c". En outre, toute implémentation cachée ou d'autres fonctions privées se trouvent dans "foo.c", mais sont marquées comme static, par exemple static int foo_internal_function(int i);. Les fonctions marquées static peuvent uniquement être référencées dans le fichier dans lequel elles existent, pas dans les autres.

Il n'y a pas d'espaces de noms formels, bien que vous puissiez obtenir le même résultat avec des préfixes de noms de fonctions, tels que Foo_discombobulate_developers(). Il n'y a pas de classes, bien que vous puissiez au moins obtenir des effets d'encapsulation avec les fichiers.Il n'y a pas de hiérarchie extensible, juste des fichiers et des fonctions.

C n'a rien à voir avec l'organisation des langages suivants, mais beaucoup de très bons programmes y ont été écrits. Soyez prudent, commentez tout ce qui prête à confusion (et en C il y a des risques de confusion) et gardez de bonnes notes.

+3

+ 1 pour comprendre la bonne façon d'API publique et privée. Utilisez static pour masquer toutes les fonctions non exportées.Et créer votre propre espace de nom pour le module (préfixe commun à tous les symboles exportés) est quelque chose que vous * devriez * faire. – u0b34a0f6ae

3

Eh bien, utilisez C++ si vous voulez faire du OO.

Si vous voulez vraiment utiliser uniquement C, sans OO, divisez votre logique sur plusieurs fichiers et considérez chaque fichier source comme un seul objet. Ainsi, chaque fichier ne contiendrait qu'une structure et des fonctions étroitement liées à cette structure unique.

+0

Exactement - un objet est juste des données et des opérations sur ces données qui implémentent une responsabilité bien définie. –

8

« Fichiers avec une quantité infinie de fonctions »

Qu'est-ce que vous voulez vraiment est des fichiers avec un ensemble bien défini et limité de fonctions. C'est ce qu'on appelle modular programming. L'idée est que vous les fonctions de groupe basées sur des fonctionnalités en une seule unité de compilation et de définir les prototypes de fonctions dans un en-tête:

.h:

int GetFoo(); 

Foo.c:

int GetFoo() 
{ 
    ... 
} 

Son quelque peu similaire à la façon dont vous regrouperiez un ensemble de méthodes en une seule classe. La principale différence est qu'il peut-ou-peut-être pas une chose sur laquelle vous travaillez à un moment donné. C'est-à-dire que vous pouvez toujours faire une programmation essentiellement "orientée objet" en C. Votre objet, cependant, devient un paramètre de votre module. Voici une approche:

Bar.h:

typedef int BAR_OBJ 

BAR_OBJ MakeBar(); 

int GetBarSize(BAR_OBJ); 

void DoFooToBar(BAR_OBJ, ...) 

Bar.c

struct BarDetails 
    { 
     int isFree; 
     int size; 
     ... 
     // other info about bar 
    }; 

    static BarDetails arrayOfBars[...]; // 

    BAR_OBJ MakeBar() 
    { 
     // search BarDetails array, find free Bar  
    } 

    int GetBarSize(BAR_OBJ obj) 
    { 
     return arrayOfBars[obj]; 
    } 

    void DoFooToBar(BAR_OBJ, ...) 
    { 
     // lookup bar obj and do something 
    } 
+0

Une question de style concernant votre code: "#define BAR_OBJ int" devrait être "typedef int BAR_OBJ" car il est plus clair quelle est votre intention (créer un nouveau type équivalent à int) et il y a probablement un cas où le premier Effets secondaires. De plus, vous n'avez généralement pas besoin d'utiliser extern sur les déclarations de fonction, mais je suppose que cela ne fait pas de mal d'être explicite. – Falaina

+0

oui, vous avez raison. mettre à jour le code. –

+0

'extern int GetFoo();' est faux. – u0b34a0f6ae

1

Il y a GObject pour POO-ish C, mais le programme structuré bien conçu ne devrait pas être plus difficile à lire/maintenir que l'équivalent OOP.

2

est ici un modèle qui apparaît en C fréquemment que émule POO:

Tenir compte d'une classe nommée MyClass.

/* MyClass.h or myclass.h */ 

#ifndef MYCLASS_H 
#define MYCLASS_H 

struct myclass_s; 
typedef struct myclass_s myclass_t; 

myclass_t * myclass_new(); 
void delete_myclass(myclass_t *); 

    // Method int doMyStuff(int arg1,int arg2) 
int myclass_doMyStuff(myclass_t *, int arg1, int arg2); 

#endif //MYCLASS_H 

Le fichier d'en-tête définit le type myclass_t, mais masque l'implémentation myclass_s. Cette exigence quelque peu incommode d'avoir deux noms vient de C ayant des structures dans un espace de noms séparé, tandis que dans les structures C++ sont dans le même espace de noms que tous les autres types. Le code est destiné à fonctionner en C et C++. Voici le fichier .c correspondant:

/* MyClass.c or myclass.c */ 

#include "myclass.h" // Or MyClass.h 

struct myclass_s { 
    int exampleField; 
}; 

myclass_t * myclass_new() 
{ 
    myclass_t * o=(myclass_t*)malloc(sizeof(myclass_t)); 
    // Initialize o here. 
    return o; 
} 

void myclass_delete(myclass_t * o) 
{ 
    // Do any cleanup needed on o here. 
    free(o); 
} 

int myclass_doMyStuff(myclass_t * o,int arg1,int arg2) 
{ 
    // ... 
} 

L'héritage et la liaison dynamique sont également possible de faire en C, mais ils sont un peu plus impliqués. Le modèle ci-dessus, ou n'importe quel modèle qui modélise la POO, n'est pas toujours la meilleure façon de faire les choses en C, alors essayez de ne pas vous accrocher à la façon de penser centrée sur la classe. Pourtant, ce modèle est parfois utile. Par exemple, libpng utilise quelque chose de proche (ils font aussi des 'exceptions' en utilisant setjmp/longjmp, ce que je déconseille).