Partage
  • Partager sur Facebook
  • Partager sur Twitter

La POO et le C

Le clash !

    25 avril 2011 à 21:29:50

    Citation : Pouet_forever

    Tu as mal lu, utiliser un void* comme pointeur de fonction est indéfini, pas le void* lui-même. :-°



    :p mmhhh... donc on cast ensuite pour être tranquille, c'est bien cela ?
    • Partager sur Facebook
    • Partager sur Twitter
      25 avril 2011 à 23:14:57

      Heuuu, non. Le pointeur void* est un pointeur générique, il peut pointer sur tous les types sauf les pointeurs de fonctions. Pas de cast ni rien. :)
      • Partager sur Facebook
      • Partager sur Twitter
        25 avril 2011 à 23:57:16

        +1
        Pour les pointeurs fonctions, c'est void * () ?
        • Partager sur Facebook
        • Partager sur Twitter
          26 avril 2011 à 0:00:59

          Non, les pointeurs de fonction ils doivent avoir le même 'prototype' que la fonction pointée.
          Si j'ai une fonction 'int fct(int a, char b)' mon pointeur de fonction devra être de type 'int (* pointeur)(int, char)'. :)
          • Partager sur Facebook
          • Partager sur Twitter
            26 avril 2011 à 7:27:36

            Bonjour,

            Il y en a sur ce topic qui mélangent un peu tout. La POO, c'est juste une méthode de programmation nécessitant l'héritage, le polymorphisme et l'encapsulation.

            L'héritage et l'encapsulation, on peut le simuler en C avec des structures opaques. Le polymorphisme, c'est un petit peu plus délicat, car cela signifie que l'on doit trouver un moyen (préprocesseur ou génération automatique de code avant la compilation) pour qu'une fonction prenne implicitement un paramètre "this" donnant accès à une vtable qui n'est d'autre qu'un tableau de pointeurs de fonction, afin de résoudre dynamiquement l'appel.

            Ca a déjà été évoqué, mais il suffit de regarder le framework Gobject, qui est écrit en C.

            Le reste (exceptions, templates, surcharge de méthodes, surcharge d'opérateur, etc.), ce n'est que du sucre syntaxique permis par le langage, ça n'a aucun rapport avec l'OO.
            • Partager sur Facebook
            • Partager sur Twitter
              26 avril 2011 à 7:38:45

              Pour l'héritage il faut aussi faire hériter les fonctions. Ou alors, tu mets la structure parente dans la structure pour l'héritage.
              • Partager sur Facebook
              • Partager sur Twitter
                28 avril 2011 à 16:11:40

                Eh bien, bonjour avant toute chose. J'ai réouvert un livre tout poussiéreux venant de ma bibliothèque du C, contenant le C en norme C99 et ANSI. Et j'avoue y voir plus clair désormais quant à l'utilisation du "void *".

                En ce qui concerne la POO : oui, donc il faut du polymorphisme, de l'héritage et de l'encapsulation. Mon programme tourne presque, je pense le livrer ici d'ici peu (le temps de le rendre plus lisible et plus... utilisable) pour ceux et celles qui sont sceptiques quand à la transcription de l'OO en C.

                En ce qui concerne (je sais, c'est un tout petit peu HS, maiiis... :p j'ai pas résisté !) la surcharge (qui pourrait peut-être être utilisée comme mécanisme pour le polymorphisme justement) voici un exemple (massacré) de codage :

                Citation

                #include <stdio.h>
                #include <stdlib.h>
                #include <stdarg.h>
                
                /**
                 * Programme illustrant une façon de faire du polymorphisme en C
                 */
                
                /**
                 * Déclaration d'une structure Nombre, contenant soit un réel,
                 * soit un entier.
                 */
                typedef enum {ENTIER, REEL} Type;
                typedef struct Nombre {
                	Type typeNb;
                	union {
                		int i;
                		double d;
                	} contenu;
                } Nombre;
                
                /**
                 * On souhaite traîter dynamiquement le problème.
                 * Prototype des fonctions New et Del
                 */
                
                Nombre * New(Type, ...);
                void Del(Nombre**);
                
                /**
                 * On va afficher les nombres avec une fonction
                 * polymorphe affiche
                 */
                
                void affiche(Nombre*);
                
                int main() {
                	Nombre * entier = NULL;
                	Nombre * reel = NULL;
                
                	entier = New(ENTIER, 3);
                	reel = New(REEL, 3.25);
                
                	affiche(entier);
                	affiche(reel);
                
                	Del(&entier);
                	Del(&reel);
                
                	entier = New(REEL, 4.33);
                	affiche(entier);
                	Del(&entier);
                
                	return EXIT_SUCCESS;
                }
                
                Nombre * New(Type ceType, ...) {
                	va_list ap;
                	Nombre * This = NULL;
                
                	This = malloc(sizeof(Nombre));
                
                	va_start(ap, ceType);
                
                	switch(ceType) {
                		case ENTIER:
                			This->contenu.i = va_arg(ap, int);
                			This->typeNb = ENTIER;
                			break;
                		case REEL:
                			This->contenu.d = va_arg(ap, double);
                			This->typeNb = REEL;
                			break;
                		}
                
                	va_end(ap);
                	return This;
                }
                
                void Del(Nombre **This) {
                	free(*This);
                	*This = NULL;
                }
                
                void affiche(Nombre *This) {
                	switch(This->typeNb) {
                		case ENTIER:
                			printf("Entier : %d\n", This->contenu.i);
                			break;
                		case REEL:
                			printf("Réel : %f\n", This->contenu.d);
                			break;
                		default:
                			printf("Type inconnu\n");
                	}
                }
                


                Bon ok, ce code est "crade" (notamment les tests d'allocation mémoire qui ne sont effectués etc.) mais le cœur y est, nan ? :-° voilà grosso modo, comment je m'en sors à ce niveau-là... Le truc de la vraie fonction polymorphe réside dans la façon de créer la structure Nombre (avec ma fonction New). En fait, il semblerait qu'il ne soit possible de bricoler de la surcharge que si l'on définit proprement le type d'objet qu'on désire au moment de sa création. Après, la surcharge est possible... La contrainte à payer (au moment de la création dynamique) est bien faible, je trouve :p et même si la responsabilité dans l'étape de création revient au programmeur, je trouve que la solution est plutôt efficace ^^

                Pour ce qui est de l'OO en C : ben ma foi, il faut jouer avec : le préproc', la compilation séparée, les TAD (types abstraits de données), les pointeurs... et évidemment éviter de recopier "la syntaxe du C++", autrement dit : adapter la syntaxe au langage C.

                À suivre...
                • Partager sur Facebook
                • Partager sur Twitter
                  28 avril 2011 à 17:32:15

                  Citation : heizmann


                  Bon ok, ce code est "crade" (notamment les tests d'allocation mémoire qui ne sont effectués etc.) mais le cœur y est, nan ? :-° voilà grosso modo, comment je m'en sors à ce niveau-là... Le truc de la vraie fonction polymorphe réside dans la façon de créer la structure Nombre (avec ma fonction New).



                  On se rapproche de la surcharge de fonction en effet, avec l'inconvénient que le compilateur ne peut pas effectuer de vérification aux niveaux des types des arguments variables. Sinon, je suis curieux de voir le reste :)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    28 avril 2011 à 20:49:03

                    Bonjour à tous,
                    Intéressant débat.

                    Je serais curieux de voir comment on simule l'encapsulation. Parce que les contrôles d'accès ne sont vérifiées que par le compilateur. A l'exécution, le public et le private n'existent plus, il y a des méthodes c'est tout. En C, rien ne nous interdit d'appeler les fonctions qu'on veut, donc il ne peut pas y avoir de contrôle d'accès. Ça ne peut reposer que sur des conventions de nommage, facilement contournables et donc sans intérêt pratique.

                    Mais bon, dans la mesure où les contrôles d'accès ne sont qu'un bonus pour guider l'utilisateur d'une API, ce n'est finalement pas très grave. En tant que bons hackers, on peut s'en passer, tout comme les bons tireurs n'ont plus besoin de sécurité sur leurs armes.

                    Pour le reste, j'ai déjà expérimenté certaines choses pour m'amuser. LE code devient vite crade, mais c'est pédagogiquement très intéressant, pour comprendre comment fonctionnent à bas niveau les mécanismes OO, et par extension les autres mécanismes du C++ comme les exceptions. C'est aussi là qu'on se rend compte de certains manques à mon avis complètement idiots du C++, comme par exemple l'interdiction d'appeler les constructeurs d'une même classe en cascade (notons que je suis plutôt un amateur de java, donc certains points particuliers du C++ me paraissent être de véritables hérésies)

                    Exceptions: avec setjmp et longjmp... par contre ça devient vite le bordel avec l'allocation dynamique... C'est là qu'on se rend comtpe à quel point les desctucteurs ont été une magnifique invention, et à quel point les systèmes de GC sont encore bien mieux que ça puisqu'ils passent complètement par-dessus le problème.

                    Métodes: il suffit de créer des fonctions qui prennent un pointeur this en premier argument

                    Héritage: il suffit que la sous-classe reprenne les mêmes propriétés que la classe mère, dans le même ordre, et surtout qu'ils soient aux mêmes offsets. LE plus simple étant d'ajouter les nouvelles propriétés après celle de la classe mère.

                    Polymorphisme: en utilisant des tables de fonctions virtuelles. En principe le pointeur vers la vtable est le premier de la structure.

                    Méthode abstraite: un espace libre dans une vtable, qui pointe sur NULL au lieu d'une vraie fonction, pour que ça crash plus rapidement au cas où on l'appelle par erreur...

                    Surcharge d'opérateur: c'est juste un bonus syntaxique

                    Surcharge de méthode: pareil, c'est aussi un bonus syntaxique... comme déjà montré dans un post précédent, essayer d'en faire c'est vraiment du gros bidouillage.

                    Redéfinition de méthode: il suffit de faire des vtables dérivées qui vont bien...

                    Opérateur instanceof: à peu de frais, on peut s'en faire un avec une boucle et des tests sur le pointeur de vtable, si on prévoit que chaque vtable possède un pointeur vers la vtable de sa superclasse. Si on est plus mazo on peut simuler du RTTI un peu plus évolué.

                    Programmation générique avec type erasure: le void* suffit largement, sauf si on doit gérer les types primitifs (ce qui permet de comprendre pourquoi les génériques de java ne peuvent pas utiliser les types primitifs; en cela, les templates du C++ constituent plus une armée de moines copistes intelligents que de la véritable programmation générique, puisque chaque classe et chaque fonction est recopiée pour chaque type utilisée (ne me tuez pas, je ne suis pas un expert C++ et je n'ai pas lu stroustrup))

                    Là où ça commence à devenir vraiment intéressant, c'est pour les interfaces. Là je commence à avoir du mal de comprendre comment ça fonctionne exactement. Définir une interface c'est pas compliqué (juste une vtable de plus avec uniquement des méthodes abstraites), c'est ensuite que je coince. Si par exemple j'ai deux interfaces I1 et I2, une classe A qui implémente ces deux interfaces, comment un pointeur sur I1 pointant en réalité sur une instance de A peut-il être converti en pointeur sur I2 ? Ou en d'autre termes, comment fonctionne dynamic_cast en C++, ou ce genre de cast en java ?
                    • Partager sur Facebook
                    • Partager sur Twitter
                      28 avril 2011 à 21:01:52

                      Citation : QuentinC 2

                      Je serais curieux de voir comment on simule l'encapsulation.


                      Comme ça :
                      /* class.h */
                      
                      struct A {
                          /* public */
                          void (* const f1)(int);
                          char (* const f2)(void);
                      };
                      

                      /* class.c */
                      
                      struct _A {
                          /* public */
                          void (* f1)(int);
                          char (* f2)(void);
                          /* private */
                          int x;
                          int y;
                      };
                      

                      Ton objet est représenté en interne par une struct _A *, mais tu ne présentes à l'utilisateur qu'un struct A *.

                      C'est la même astuce que pour l'héritage, en fait.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 avril 2011 à 21:58:16

                        Re ! Alors, maintenant, un petit coup d'encapsulation ^^ et pour les pressés je préviens d'avance, encore une fois je vous donne un code "crade"... mmhhh :-° il faudra encore patienter un peu avant d'avoir quelque chose de joli en C, concernant l'OO. Mais le cœur, encore une fois, y est !

                        L'interface Point.h
                        #ifndef POINT_H
                        #define POINT_H
                        
                        typedef struct Point {
                        	struct sCoord *aCoord;
                        	void(*Del)(struct Point **);
                        	int(*getX)(struct Point *);
                        	int(*getY)(struct Point *);
                        	void(*set)(struct Point *, int, int);
                        } Point;
                        
                        extern Point *New_Point(int, int);
                        
                        #endif /* POINT_H */
                        


                        L'implémentation Point.c
                        #include <stdlib.h>
                        #include "Point.h"
                        
                        struct sCoord {
                        	int x;
                        	int y;
                        };
                        
                        static void Del_(Point **);
                        static int getX_(Point *);
                        static int getY_(Point *);
                        static void set_(Point *, int, int);
                        
                        Point *New_Point(int x_, int y_) {
                        	Point *This = NULL;
                        	struct sCoord *Priv = NULL;
                        
                        	This = malloc(sizeof(Point));
                        	if(This == NULL) return NULL;
                        	Priv = malloc(sizeof(struct sCoord));
                        	if(Priv == NULL) goto abort_code;
                        
                        	Priv->x = x_;
                        	Priv->y = y_;
                        
                        	This->Del = Del_;
                        	This->getX = getX_;
                        	This->getY = getY_;
                        	This->set = set_;
                        
                        	This->aCoord = Priv;
                        	return This;
                        
                        	abort_code:
                        	free(This);
                        	This = NULL;
                        	return NULL;
                        
                        	
                        }
                        
                        void Del_(Point **This) {
                        	free((*This)->aCoord);
                        	(*This)->aCoord = NULL;
                        	free(*This);
                        	*This = NULL;
                        }
                        
                        int getX_(Point *This) {
                        	return This->aCoord->x;
                        }
                        
                        int getY_(Point *This) {
                        	return This->aCoord->y;
                        }
                        
                        void set_(Point *This, int x_, int y_) {
                        	This->aCoord->x = x_;
                        	This->aCoord->y = y_;
                        }
                        


                        Exemple d'utilisation : main.c
                        #include <stdio.h>
                        #include <stdlib.h>
                        #include "Point.h"
                        
                        int main() {
                        	Point *ptr = NULL;
                        
                        	ptr = New_Point(5, 4);
                        	if(ptr == NULL)
                        		fprintf(stderr, "Erreur d'allocation mémoire\n");
                        	printf("Point (x,y)=(%d,%d)\n", ptr->getX(ptr), ptr->getY(ptr));
                        	ptr->Del(&ptr);
                        	return EXIT_SUCCESS;
                        }
                        


                        Notez qu'ici, dans ce code, l'encapsulation est rendue en faisant en sorte qu'à la construction de l'objet Point, on alloue non seulement de la mémoire pour la structure Point, mais aussi pour... la structure "sCoord". Ici, pas d'erreur à la compilation, car on a définit dans "struct Point" (dans l'interface) un pointeur vers la structure des coordonnées, or les pointeurs ayant une taille bien définie en C... bref ;) je vous laisse analyser tout cela.

                        Une astuce pour la portée des variables pour les utilisateurs du gcc : par ici (je ne sais pas si ça marche, jamais essayé en fait :p )

                        Ce qu'il manque à ce code : un petit exemple de surcharge au niveau des méthodes de la structure-objet, et aussi une petite surcharge par exemple au niveau du "New" (pour éviter de faire New_Point). Reste à voir comment faire pour coder ça proprement, avec une manière standard de le faire, histoire qu'ensuite on s'y retrouve un peu dans tout ce fourbi.

                        Autre chose qu'on pourrait tenter : créer un fichier à inclure dans l'interface et l'implémentation (dont le nom serait, au hasard, "Objet.def" :-° ), et contenant quelques macros et X-macros servant à générer le code des interfaces/implémentations :) ainsi, ça faciliterait grandement la maintenance de ces fichiers, vous ne pensez-pas ?

                        Prochaine intervention : probablement le préprocesseur ;) et ses astuces dans la modélisation objet en C... encore inconnus pour certains :p (je l'espère, hihi... faut bien quand même qu'on partage des astuces, nan ? :lol: )
                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 avril 2011 à 22:07:31

                          Ah, ben tu viens de t'amuser à implémenter la réponse que j'ai donnée juste avant ton post, c'est sympa :p

                          J'avais suggéré l'ajout du qualificateur const pour éviter que l'utilisateur ne fasse bêtement :
                          objet->methode = NULL
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 avril 2011 à 22:19:26

                            Citation : MaitreZur

                            Ah, ben tu viens de t'amuser à implémenter la réponse que j'ai donnée juste avant ton post, c'est sympa :p

                            J'avais suggéré l'ajout du qualificateur const pour éviter que l'utilisateur ne fasse bêtement :

                            objet->methode = NULL
                            


                            :o oh, je m'en excuse... :p mais la façon de faire n'est pas tout à fait identique :euh: dans mon cas, les attributs font partie de la "classe", ça me semble plus... cohérent pour le traitement "objet".
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              29 avril 2011 à 10:57:28

                              Je vois pas l'intérêt d'implémenter des mécanismes complexes d'OO en C, le langage n'est pas fait pour ça.
                              Quand on a besoin de ce genre de mécanismes, on dispose d'un compilateur C++.

                              En revanche, avoir une approche objet est possible dans n'importe quel langage, même en assembleur, c'est surtout ça qu'il faut comprendre.
                              On peut faire du code Java qui n'est pas du tout objet, et du code brainfuck qui l'est. C'est principalement une question de conception.
                              Perso, j'ai fait un code C embarqué complet pour un projet où chaque module était bien séparé, des variables toujours privées avec static, des méthodes publiques et privées, et des objets de code indépendants, réutilisables. En clair, ce qui est propre et ne gêne pas la lecture.

                              En revanche, implémenter de l'héritage, du polymorphisme, etc en C, ça n'a strictement aucun intérêt, ça nuit à la lisibilité, et quand c'est utile, le C++ est toujours disponible...
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Anonyme
                                29 avril 2011 à 12:32:19

                                Citation : Gwen-Haël

                                Je vois pas l'intérêt d'implémenter des mécanismes complexes d'OO en C, le langage n'est pas fait pour ça.
                                Quand on a besoin de ce genre de mécanismes, on dispose d'un compilateur C++.
                                (...)
                                En revanche, implémenter de l'héritage, du polymorphisme, etc en C, ça n'a strictement aucun intérêt, ça nuit à la lisibilité, et quand c'est utile, le C++ est toujours disponible...



                                ça ce discute ça. Dans tous les cas, ici, on ne parle pas d'interet mais de faisabilité. C'est juste "fun" de le simuler. N'as tu donc jamais rien programmé "pour le plaisir" ?

                                De plus, ça m'étonne tout de même que le projet GNU ce soient embêtés a programmer GObject juste pour le fun. Si ils ont mis en place tout un système de conception objet en C, j'imagine qu'il y avais des raisons derrière ...
                                • Partager sur Facebook
                                • Partager sur Twitter
                                Anonyme
                                  29 avril 2011 à 12:49:23

                                  C'est fun, ouais, mais ça reste très sale (un peu à l'image de GNU, si vous me permettez ce petit troll. Merci, pas taper).

                                  Pourquoi GObject? Parce qu'à l'époque, il y avait de lourds problèmes de portabilité du C++, et coder en C++ aurait restreint la compatibilité de leurs codes.
                                  Accessoirement, ils ont aussi introduit des mécanismes supplémentaires, qu'on retrouve avec Qt en C++ par exemple (signaux, etc...).

                                  GObject c'est quasiment un langage à part au final, mais dont le code se compile avec GCC. D'ailleurs, il ne compile qu'avec ça il me semble.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    29 avril 2011 à 12:53:47

                                    J'avais pourtant vu un programme qui transforme un code C++ en C.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      29 avril 2011 à 13:39:57

                                      @Gwen-Haël : mmhh... ici il n'est pas question de faire des zéros des pros de la conception objet en C :ange: c'est un débat sur le plaisir de programmer (comme le signale ChristopheG) !!!

                                      Citation : Terbaddo

                                      J'avais pourtant vu un programme qui transforme un code C++ en C.



                                      :-° dans le même genre, j'ai vu aussi des internautes américains parler de code transformant du C# en C :p !!!
                                      (je veux même pas savoir si ça existe ou pas... d'ailleurs, si c'était le cas, je crois que je me
                                      trollerais moi-même en faisant un tuto sur GObject :p ou COS de Deniau, au choix)

                                      Re les gens ! Alors voici, dans la lignée des codes crades deux produits quasi-maisons, réadaptés de ce que
                                      j'ai pu pêcher sur les forums de nos amis américains ! :euh: âmes sensibles, s'abstenir d'ouvrir
                                      les spoils...

                                      Citation : heizmann *self

                                      Attention ! Danger ! Réservé aux g33ks-3l33t :ninja:



                                      Une façon d'implémenter des tables de fonctions virtuelles en fichiers !

                                      Fichier main.c :
                                      #include <stdio.h>
                                      #include <stdlib.h>
                                      #include <stdarg.h>
                                      
                                      /**
                                       * Le polymorphisme
                                       * Par Heizmann 
                                       */
                                      
                                      /**
                                       * Objectif : rendre compte à terme du polymorphisme
                                       * par l'utilisation de structure VTable.
                                       *
                                       * /!\ LE CODE COMPILE MAIS !!!
                                       *  - Il permet en principe de faire du polymorphisme !!
                                       *  - Il n'implémente pas un exemple de polymorphisme pour l'instant
                                       *  - La façon dont j'ai séparé 'obj.def' et cette implémentation
                                       *    est "crade" : je ne garantis aucune généricité avec ce code
                                       *    quant à la modification dans 'obj.def' des méthodes/attributs de
                                       *    l'objet.
                                       *
                                       * La maintenance (loin d'être parfaite, il faudra améliorer
                                       * le code :p) est facilitée à coups de X-macros
                                       * Il suffit de modifier 'obj.def' pour ajouter des méthodes 
                                       * (attention  risque de bugs  j'ai codé comme un 'port' héhé)
                                       */
                                      
                                      /**
                                       * Déclaration d'une structure Point
                                       */
                                      struct Point;
                                      
                                      /**
                                       * X-macro déclarant le prototype des implémentations des fonctions
                                       * membres
                                       */
                                      #define X(OBJET,TYPE,METH) \
                                      TYPE OBJET##_##METH(struct OBJET*);
                                      #include "obj.def"
                                      
                                      /**
                                       * Le cœur ( <3 ) du polymorphisme : X-macro définissant le type
                                       * VTable pour la classe Point
                                       */
                                      struct Point_VTable {
                                      #define X(OBJET,TYPE,METH) \
                                      TYPE (*METH)(struct OBJET *);
                                      #include "obj.def"
                                      };
                                      
                                      /**
                                       * Ah ! Voici enfin la classe Point, dont les méthodes sont
                                       * dans une VTable (celle des objets Point)
                                       */
                                      struct Point {
                                      	struct Point_VTable vtable;
                                      	int x;
                                      	int y;
                                      };
                                      
                                      
                                      /* Une petite astuce concoctée par moi 
                                       * permettant d'assigner un alias vers la bonne méthode
                                       * à appeler (sissi  et essayer d'expanser les X-macro,
                                       * on obtient en plus des alias qui ne sont pas des #define :p)
                                       */
                                      #define TABLVIRT(OBJET,ALIAS) \
                                      struct OBJET##_##VTable ALIAS
                                      
                                      #define X(OBJET,TYPE,METHODE) . METHODE = & OBJET##_##METHODE,
                                      TABLVIRT(Point,POINT) = {
                                      #include "obj.def"
                                      };
                                      
                                      /**
                                       * Encore <:o) !! ...une X-macro.
                                       * celle-ci a pour rôle de définir la définition de chaque
                                       * implémentation de fonctions via le fichier 'obj.def' (on peut
                                       * dire QU'À TERME, obj.def serait notre VRAI objet, tandis que ce
                                       * fichier serait plutôt un fichier de 'MÉCANISMES D'IMPLÉMENTATIONS' !!)
                                       */
                                      #define X(OBJET,TYPE,METH) \
                                      TYPE OBJET##_##METH(struct OBJET *This) \
                                      XCODE(OBJET,METH)
                                      #include "obj.def"
                                      
                                      /**
                                       * P'tite macro pour se faciliter la vie côté allocation mémoire
                                       * (définie dans 'obj.def')
                                       */
                                      ALLOC(Point)
                                      
                                      /**
                                       * Macro NEW ! Résolue à coups de X-macros imbriquées, ça réduit
                                       * la taille du code d'une façon non insignifiante !
                                       * autre avantage : ce sont des X-macros (X : pour les méthodes ;
                                       * XATTR : pour les attributs), et... :o) ça facilite
                                       * la maintenance (il suffit pour rajouter des méthodes/attributs de
                                       * modifier EN THÉORIE (/!\ rappel : ce code est crade) l'objet via
                                       * 'obj.def'
                                       */
                                      NEW(Point, int x_, int y_) {
                                      #define X(OBJET,TYPE,METH) \
                                      new##OBJET->vtable. METH = OBJET##_##METH;
                                      #include "obj.def"
                                      #define XATTR(OBJET,A,A_) \
                                      new##OBJET-> A = A_;
                                      #include "obj.def"
                                      	return newPoint;
                                      }
                                      
                                      /**
                                       * Notre libérateur de mémoire
                                       */
                                      void Point_Free(struct Point **This) {
                                      	(*This)->vtable.Dtor(*This);
                                      	free(*This);
                                      	printf("Objet détruit\n");
                                      }
                                      
                                      /**
                                       * Un petit test ???  Enjoy !
                                       */
                                      int main() {
                                      	struct Point *ptr = Point_New(Point_Alloc(), 5, 3);
                                      
                                      	printf("x vaut %d\n", POINT.getX(ptr));
                                      	printf("y vaut %d\n", ptr->vtable.getY(ptr));
                                      
                                      	Point_Free(&ptr);
                                      	return 0;
                                      }
                                      


                                      Le fichier 'obj.def' (censé modéliser l'objet)
                                      #define NEW(OBJET, ...) \
                                      struct OBJET *OBJET##_##New(struct OBJET *new##OBJET, __VA_ARGS__)
                                      
                                      #define ALLOC(OBJET) \
                                      struct OBJET * OBJET##_##Alloc() { \
                                      	return malloc(sizeof(struct OBJET)); \
                                      }
                                      
                                      #define XCODE(O_,M_) CODE##_##O_##_##M_
                                      
                                      #define CODE_Point_getX { return This->x; }
                                      #define CODE_Point_getY { return This->y; }
                                      #define CODE_Point_Dtor { printf("Appel du destructeur\n"); \
                                      	return This; }
                                      
                                      /*
                                      Le destructeur permet de désallouer (si nécessaire ce qui n'est pas le cas ici)
                                      proprement les attributs qui ont demandé de l'allocation mémoire (comme des chaînes
                                      de caractères, par exemple, ou encore un tableau dynamique  à vous de voir...)
                                      */
                                      
                                      #ifdef X
                                      X(Point, int, getX)
                                      X(Point, int, getY)
                                      X(Point, struct Point *, Dtor)
                                      #endif
                                      #undef X
                                      
                                      #ifdef XATTR
                                      XATTR(Point, x, x_)
                                      XATTR(Point, y, y_)
                                      #endif
                                      #undef XATTR
                                      



                                      Attention, ce qu'il faut retenir c'est pas la manière crado de coder, c'est plutôt de réinvestir
                                      ça pour en faire un code propre. :lol: si y'en a qui sont assez motivés... au fait, ça pourrait
                                      déboucher sur un tuto tout ça, ça pourrait être sympa ? o_O euh... :-° non ? (en vérité : plus un tuto sur le paragidme objet, et un exemple d'implémentation de ce paradigme dans un langage, euh au hasard : le C ^^ )

                                      ...sans plus attendre, deuxième code (moins crade, quoique... peut-être que certains me jetteront
                                      une pierre pour faire du code illisible :diable: gnnniark !)

                                      #include <stdio.h>
                                      #include <stdlib.h>
                                      
                                      /**
                                       * Tentative de polymorphisme en C (code compatible C90 C99 ANSI-C)
                                       * Par : Heizmann 
                                       *
                                       * La tentative utilise non pas une bête structure
                                       * pour la table virtuelle (pour lier dynamiquement
                                       * une fonction à l'objet au moment de sa création) mais...
                                       * ...un pointeur de pointeurs de fonctions !
                                       */
                                      
                                      /**
                                       * On a ici notre structure "représentant" une classe,
                                       * disons la classe A
                                       * lettre est un attribut public (pas privé, pour éviter de compliquer
                                       * inutilement les choses)
                                       * (vptr : pointeur des tables virtuelles)
                                       *  *** vptr *** : le cœur du polymorphisme, c'est...
                                       * ...un pointeur de pointeurs de fonctions !!!
                                       * ...autrement dit : un pointeur vers un tableau de fonctions !
                                       */
                                      struct A {
                                      	char lettre;
                                      	int (**vptr)();
                                      };
                                      
                                      /**
                                       * Deux prototypes de fonctions vers lesquels il faudra se rediriger
                                       * pour appliquer le polymorphisme
                                       */
                                      int affiche();
                                      int affiche2();
                                      
                                      /**
                                       * on déclare statiquement (portée) deux pointeurs vers des tableaux de
                                       * fonctions
                                       */
                                      static int (*vtbl[])() = {
                                      	&affiche
                                      };
                                      static int (*vtbl2[])() = {
                                      	&affiche2
                                      };
                                      
                                      /**
                                       * Le prototype des deux fonctions qui permettent de créer
                                       * un objet en mémoire
                                       */
                                      struct A * New();
                                      struct A * New2();
                                      
                                      /**
                                       * Une des deux fonctions New qui va, via This->vptr,
                                       * assigner la bonne association vers la bonne implémentation
                                       * d'affichage
                                       */
                                      struct A * New(This, car)
                                      	register struct A * This;
                                      	char car;
                                      {
                                      	if(This == 0) This = malloc(sizeof(struct A));
                                      	This->vptr = vtbl;
                                      	This->lettre = car;
                                      	return This;
                                      }
                                      
                                      int affiche(struct A *This) {
                                      	printf("La lettre est : %c\n", This->lettre);
                                      }
                                      
                                      struct A * New2(This, car)
                                      	register struct A * This;
                                      	char car;
                                      {
                                      	if(This == 0) This = malloc(sizeof(struct A));
                                      	This->vptr = vtbl2;
                                      	This->lettre = car;
                                      	return This;
                                      }
                                      
                                      int affiche2(struct A *This) {
                                      	printf("La lettre est : %c (polymorphisme)\n", This->lettre);
                                      }
                                      
                                      /**
                                       * Un petit #define pour faciliter le passage à la "table virtuelle"
                                       */
                                      #define AffichePoly(OBJ) vptr[0](OBJ)
                                      
                                      int main() {
                                      	struct A *ptr = NULL;
                                      	struct A *ptr2 = NULL;
                                      
                                      	ptr = New(ptr, 'A');
                                      	ptr2 = New2(ptr2, 'B');
                                      
                                      	/**
                                      	 * Affiche : 'A'
                                      	 */
                                      	ptr->AffichePoly(ptr);
                                      
                                      	/**
                                      	 * Affiche : 'B'
                                      	 */
                                      	ptr2->AffichePoly(ptr2);
                                      
                                      	/**
                                      	 * Affiche : 'A' (poly)
                                      	 */
                                      	ptr->AffichePoly(ptr2);
                                      
                                      	/**
                                      	 * Affiche : 'B' (poly)
                                      	 */
                                      	ptr2->AffichePoly(ptr);
                                      
                                      	/**
                                      	 * Désallocation "à la main" (pour ne pas surcharger
                                      	 * le code  ('surcharger', ouah, la blague :p)
                                      	 */
                                      
                                      	free(ptr);
                                      	free(ptr2);
                                      
                                      	return EXIT_SUCCESS;
                                      }
                                      


                                      J'ose ajouter que ces deux codes compilent sans broncher avec gcc, plus les flags 'ansi' et
                                      '-pedantic' :magicien: c'est pas beau ça ???

                                      Prochaine étape : essayer de faire un code plus propre, avec :

                                      • objet modélisé dans un fichier de 'X-macros' (comme le 'obj.def' de l'exemple :waw: )
                                      • compilation séparée (pour l'encapsulation)
                                      • ...et utilisation des X-macros dans les fichiers interfaces/implémentations ('monObj.h' et 'monObj.c')


                                      À suivre :) bon codage !
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        29 avril 2011 à 13:44:21

                                        IL peut y avoir un intérêt à ne pas utiliser le C++ (systèmes embarqués)... mais de toute façon, comme déjà dit, la question ici n'est pas de savoir si c'est concrètement utile, mais juste si c'est faisable et si oui comment.

                                        Citation

                                        J'avais pourtant vu un programme qui transforme un code C++ en C.


                                        A mon avis ce n'est pas impossible. Bon, le problème avec les générateurs automatiques c'est que souvent ça produit du code absolument inbuvable.
                                        Notons quand même qu'il existe, sauf erreur, plusieurs langages plus ou moins évolués, qui passent en interne par une étape de conversion en C.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          29 avril 2011 à 13:46:57

                                          @QuentinC : sorry pour le retard, ceci étant ;) ton post est trèèèèès intéressant ! En particulier en ce qui concerne le polymorphisme :) j'ai pu mettre au point des idées conceptuelles dans ma petite tête à ce propos, un grand merci !
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            29 avril 2011 à 14:28:14

                                            Citation

                                            @QuentinC : sorry pour le retard, ceci étant ton post est trèèèèès intéressant ! En particulier en ce qui concerne le polymorphisme
                                            j'ai pu mettre au point des idées conceptuelles dans ma petite tête à ce propos, un grand merci !   


                                            Pas de quoi! Par contre il n'y a pas encore de réponse à la seconde question que j'ai posée dans ma première participation à ce sujet, sur les interfaces et le casting. Ca risque d'être chaud là, mais c'est assurément très intéressant.

                                            L'autre sujet intéressant, c'est la programmation générique. Les templates à la C++ vs la généricité à type erasure de java et C#. Ayant été bercé au java très rapidement, j'ai tendance à ne pas trop aimer les templates C++, notamment le fait que des classes entières sont copiées alors que ce n'est techniquement pas nécessaire, et l'utilité très relative des spécialisations, sans oublier le complet ridicule des GCD et autres factorielles intégralement codées en templates.
                                            Côté généricité par type erasure en C, c'est pas compliqué: les void* se convertissent en pointeurs de n'importe quel autre type, donc ça marche et c'est suffisant pour tout type de pointeur. Pour les types primitifs et non pointeurs, ça marche pour autant que sizeof(T)<=sizeof(void*) techniquement, même si c'est effectivement des conversions un peu plus osées...

                                            Un moment donné, je m'étais imaginé inventer un nouveau langage reprenant le meilleur de l'OO en java et en ruby, et passant en interne par une conversion en C avant la compilation par GCC... mais je ne suis jamais allé plus loin faute de temps et de motivation.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Anonyme
                                              29 avril 2011 à 15:35:19

                                              Pour moi,sur la question template / generic, je dirais que la méthode java ou .net est clairement plus propre. Le gros problème en c++ est l'absence de possibilité de specifier l'interface. Les compilateur font des remplacement pur et dur et en cas d'incompatibilité cela fait des messages d'erreurs incompréhensible et long de 4km. Par contre je ne suis pas d'accord avec toi sur l'utilisation des remplage pour la metaprog. C'est super pratique pafois et si c'est bien fait il n'y a pas de soucis
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                29 avril 2011 à 17:18:23

                                                Citation : QuentinC 2


                                                Citation

                                                J'avais pourtant vu un programme qui transforme un code C++ en C.


                                                A mon avis ce n'est pas impossible. Bon, le problème avec les générateurs automatiques c'est que souvent ça produit du code absolument inbuvable.
                                                Notons quand même qu'il existe, sauf erreur, plusieurs langages plus ou moins évolués, qui passent en interne par une étape de conversion en C.


                                                Inbuvable mais compilable. Après tout, le code C est transformé en assembleur avant d'être exécutable.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  29 avril 2011 à 21:08:46

                                                  Ne vous en faites pas, je lis chaque message :D !

                                                  Concernant ce post, ci-dessus, je me demandais ce que vous préférez pour l'emploi des Vtables : les pointeurs de tableaux de fonction, ou bien les pointeurs vers des structures (contenant des pointeurs vers des fonctions) ? Ça m'intéresserait d'avoir vos avis entre autre sur :

                                                  • la lisibilité du code
                                                  • la réutilisation du code
                                                  • l'intégrité du code
                                                  • les possibilités de gestions d'erreurs si l'utilisateur fait "n'importe quoi"


                                                  :pirate: mille sabords, exprimez-vous ! :p !

                                                  Pour une question de relecture plus aisée, je fais simplement un petit 'gcc -E essai.c' sur le test rempli de X-macros ^^ (donc, le test concernant l'utilisation des pointeurs vers 'des structures VTables', pas des pointeurs vers des tableaux VTables de fonctions) :

                                                  struct Point;
                                                  
                                                  /**
                                                   * X-macro déclarant le prototype des implémentations des fonctions
                                                   * membres
                                                   */
                                                  int Point_getX(struct Point*);
                                                  int Point_getY(struct Point*);
                                                  struct Point * Point_Dtor(struct Point*);
                                                  
                                                  /**
                                                   * Le cœur ( <3 ) du polymorphisme : X-macro définissant le type
                                                   * VTable pour la classe Point
                                                   */
                                                  struct Point_VTable {
                                                  int (*getX)(struct Point *);
                                                  int (*getY)(struct Point *);
                                                  struct Point * (*Dtor)(struct Point *);
                                                  };
                                                  
                                                  /**
                                                   * Ah ! Voici enfin la classe Point, dont les méthodes sont
                                                   * dans une VTable (celle des objets Point)
                                                   */
                                                  struct Point {
                                                   struct Point_VTable vtable;
                                                   int x;
                                                   int y;
                                                  };
                                                  
                                                  /* Une petite astuce concoctée par moi 
                                                   * permettant d'assigner un alias vers la bonne méthode
                                                   * à appeler (sissi  et essayer d'expanser les X-macro,
                                                   * on obtient en plus des alias qui ne sont pas des #define :p)
                                                   */
                                                  struct Point_VTable POINT = {
                                                  . getX = & Point_getX,
                                                  . getY = & Point_getY,
                                                  . Dtor = & Point_Dtor,
                                                  };
                                                  
                                                  /**
                                                   * Encore <:o) !! ...une X-macro.
                                                   * celle-ci a pour rôle de définir la définition de chaque
                                                   * implémentation de fonctions via le fichier 'obj.def' (on peut
                                                   * dire QU'À TERME, obj.def serait notre VRAI objet, tandis que ce
                                                   * fichier serait plutôt un fichier de 'MÉCANISMES D'IMPLÉMENTATIONS' !!)
                                                   */
                                                  int Point_getX(struct Point *This) { return This->x; }
                                                  int Point_getY(struct Point *This) { return This->y; }
                                                  struct Point * Point_Dtor(struct Point *This) { printf("Appel du destructeur\n"); return This; }
                                                  
                                                  /**
                                                   * P'tite macro pour se faciliter la vie côté allocation mémoire
                                                   * (définie dans 'obj.def')
                                                   */
                                                  struct Point * Point_Alloc() { return malloc(sizeof(struct Point)); }
                                                  
                                                  /**
                                                   * Macro NEW ! Résolue à coups de X-macros imbriquées, ça réduit
                                                   * la taille du code d'une façon non insignifiante !
                                                   * autre avantage : ce sont des X-macros (X : pour les méthodes ;
                                                   * XATTR : pour les attributs), et... :o) ça facilite
                                                   * la maintenance (il suffit pour rajouter des méthodes/attributs de
                                                   * modifier EN THÉORIE (/!\ rappel : ce code est crade) l'objet via
                                                   * 'obj.def'
                                                   */
                                                  struct Point *Point_New(struct Point *newPoint, int x_, int y_) {
                                                  newPoint->vtable. getX = Point_getX;
                                                  newPoint->vtable. getY = Point_getY;
                                                  newPoint->vtable. Dtor = Point_Dtor;
                                                  newPoint-> x = x_;
                                                  newPoint-> y = y_;
                                                   return newPoint;
                                                  }
                                                  
                                                  /**
                                                   * Notre libérateur de mémoire
                                                   */
                                                  void Point_Free(struct Point **This) {
                                                   (*This)->vtable.Dtor(*This);
                                                   free(*This);
                                                   printf("Objet détruit\n");
                                                  }
                                                  
                                                  /**
                                                   * Un petit test ???  Enjoy !
                                                   */
                                                  int main() {
                                                   struct Point *ptr = Point_New(Point_Alloc(), 5, 3);
                                                  
                                                   printf("x vaut %d\n", POINT.getX(ptr));
                                                   printf("y vaut %d\n", ptr->vtable.getY(ptr));
                                                  
                                                   Point_Free(&ptr);
                                                   return 0;
                                                  }
                                                  


                                                  (je me suis permis aussi de remettre les commentaires du code du post précédent, histoire de s'y situer facilement).

                                                  @QuentinC 2 : hem... oui, j'ai lu l'autre soir pour la simulation des interfaces en C... je me demandais si, au lieu de caster, on ne ferait pas mieux d'utiliser une fonction intermédiaire qui copie l'objet, et qui réassigne temporairement sur la copie la bonne VTable... :) mmhhh ???

                                                  Les choses, je trouve, commencent à prendre forme dans ma tête, concernant la création d'un code 'propre' visant à reproduire les paradigmes de l'OO en C. o_O Je me demandais aussi au passage si l'on pourrait faire joujou ou pas avec les threads, mutex, pipes, sémaphores & messages, pour rendre 'vivants' et 'communicatifs' nos objets... :euh: ouh là ! Vite !! :p une aspirine, gniiiiark !

                                                  Par contre, en ce qui concerne l'utilisation du préprocesseur dans tout ce fourbi : je pense qu'il ne devrait servir qu'à trois choses dans le cadre de l'implémentation du paradigme OO en C :
                                                  • à créer à coups de X-Macros l'objet pour une meilleure maintenance de ce dernier via un fichier .def de l'objet
                                                  • à lever certaines exceptions à la compilation (avec #error)... je n'ai pas encore réfléchi quels exceptions pourraient être levées ni comment (tout serait plus simple si on pouvait écrire des trucs du genre : #define FOO #define BAR :p (oui oui, sur la même ligne) !
                                                  • à générer des alias pour appeler les méthodes d'un objet (personnellement, c'est un peu contraignant que de devoir faire ptrVersObj->pvrt[3](ptrVersObj, 3) par exemple, si pvrt[3] correspond à un setter pour l'objet pointé par ptrVersObj ;) )


                                                  Je m'interroge aussi sur la façon d'implémenter certains pointeurs particuliers d'un objet, tels que : *Parent, *Interface[i] par exemple, pour se référer à un parent (héritage) ou bien à une interface particulière...

                                                  Pour les interfaces : on pourrait envisager suivant la fin du paragraphe qui précède de faire des vérifications pour voir si la VTable qu'on assigne est conforme ou pas à (aux) (l')interface(s) assignée(s), à condition toutefois de séparer proprement allocation de mémoire et construction (resp. libération et destruction quand on veut bazarder l'objet) d'un objet en mémoire.

                                                  :diable: @ux petits malins qui voudraient m'empêcher de faire des goto dans mes codes : sachez que c'est une façon recevable de traiter les exceptions en C ! (faites le test par vous-même en googlelisant la toile anglosaxone et vous verrez que c'est monnaie courante)
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    30 avril 2011 à 9:45:23

                                                    Citation : heizmann


                                                    je me demandais ce que vous préférez pour l'emploi des Vtables : les pointeurs de tableaux de fonction, ou bien les pointeurs vers des structures (contenant des pointeurs vers des fonctions) ?



                                                    J'aurais tendance à préférer la structure qui a le mérite d'être nettement plus claire lors de la lecture.

                                                    Citation : heizmann


                                                    la lisibilité du code



                                                    Avec gcc -E ça va :p

                                                    Citation : heizmann


                                                    Par contre, en ce qui concerne l'utilisation du préprocesseur dans tout ce fourbi : je pense qu'il ne devrait servir qu'à trois choses dans le cadre de l'implémentation du paradigme OO en C



                                                    J'aurais ajouter son utilisation pour produire du code générique (un peu comme les templates du C++).
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      30 avril 2011 à 11:32:27

                                                      Citation : Taurre


                                                      J'aurais ajouter son utilisation pour produire du code générique (un peu comme les templates du C++).



                                                      mmhhh... :-° n'est-ce pas un peu dangereux ? Pas de contrôle de type (quoique... typeof marche avec gcc :( mais pas portable), et puis >_< il y a les effets de bords aussi...

                                                      Citation : Taurre

                                                      Avec gcc -E ça va :p



                                                      :lol: j'aurais dû voir qu'il y avait une coloration syntaxique pour les commandes, c'est pratique !

                                                      Citation : Taurre

                                                      Citation : Heizmann

                                                      je me demandais ce que vous préférez pour l'emploi des Vtables : les pointeurs de tableaux de fonction, ou bien les pointeurs vers des structures (contenant des pointeurs vers des fonctions) ?

                                                      J'aurais tendance à préférer la structure qui a le mérite d'être nettement plus claire lors de la lecture.



                                                      :p je suis parfaitement d'accord ! Mais, pour la lisibilité, s'il n'y a que ça... le truc serait quand même intéressant avec les pointeurs de pointeurs de fonctions, surtout de voir quels mécanismes on pourrait automatiser avec cette manière d'implanter la chose. ^^

                                                      Cordialement,
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        30 avril 2011 à 12:20:19

                                                        Citation : heizmann


                                                        mmhhh... :-° n'est-ce pas un peu dangereux ? Pas de contrôle de type (quoique... typeof marche avec gcc :( mais pas portable), et puis >_< il y a les effets de bords aussi...



                                                        Non, parce que le but est en fait de définir plusieurs fonctions prenant des types différents, mais d'uniformiser l'appel via une macro. Voici un exemple:

                                                        max.def




                                                        #ifndef MAX_DEF
                                                        #define MAX_DEF  1
                                                        
                                                        #define MAX_PROTOTYPE(TYPE) TYPE max_ ## TYPE (TYPE a, TYPE b)
                                                        
                                                        #define MAX_DEFINITION(TYPE) MAX_PROTOTYPE(TYPE) \
                                                        { \
                                                        	if ((a) > (b)) { \
                                                        		return (a); \
                                                        	} else { \
                                                        		return (b); \
                                                        	} \
                                                        }
                                                        
                                                        #define MAX(a, b, TYPE) max_ ## TYPE ((a), (b))
                                                        
                                                        #endif /* MAX_DEF */
                                                        



                                                        max.h




                                                        #ifndef MAX_H
                                                        #define MAX_H  1
                                                        
                                                        #include "max.def"
                                                        
                                                        MAX_PROTOTYPE (int);
                                                        MAX_PROTOTYPE (double);
                                                        
                                                        #endif /* MAX_H */
                                                        



                                                        max.c




                                                        #include "max.h"
                                                        
                                                        MAX_DEFINITION (int)
                                                        MAX_DEFINITION (double)
                                                        



                                                        main.c




                                                        #include <stdio.h>
                                                        #include <stdlib.h>
                                                        
                                                        #include "max.h"
                                                        
                                                        
                                                        int
                                                        main (void)
                                                        {
                                                        	printf ("%d\n", MAX (10, 20, int));
                                                        	printf ("%f\n", MAX (10.50, 10.40, double));
                                                        
                                                        	return EXIT_SUCCESS;
                                                        }
                                                        



                                                        Alors oui, je sais, cette fonction max est complètement inutile puisqu'elle pourrait-être implémentée via une simple macro, mais c'est juste pour l'exemple.

                                                        Le but est donc de masquer les appels à des fonctions différentes via la macro MAX et de simplifier les définitions des différentes fonctions via les macros MAX_PROTOTYPE et MAX_DEFINITION. Dans la réalité la validité des types est bel et bien assurée puisqu'on appel une fonction différente suivant le type des arguments ;)

                                                        EDIT: ne pas essayer avec un type composé de deux mots comme long long :-°
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          30 avril 2011 à 14:12:36

                                                          @Taurre: sympa ton truc, mais il n'y a aucun moyen d'inférer le type, i.e. ne pas avoir besoin de préciser le troisième paramètre de la macro ? Je suppose que non, mais ne sait-on jamais, avec quelque chose comme typeof.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            30 avril 2011 à 14:48:10

                                                            Citation : QuentinC 2


                                                            @Taurre: sympa ton truc, mais il n'y a aucun moyen d'inférer le type, i.e. ne pas avoir besoin de préciser le troisième paramètre de la macro ? Je suppose que non, mais ne sait-on jamais, avec quelque chose comme typeof.



                                                            Je ne connais pas bien l'opérateur typeof supporter par GCC, mais il donne un exemple de définition d'une macro max à cette page. Sinon, pour en revenir à mon exemple, je ne suis pas certains qu'il soit possible de concaténer le résultat de l'opérateur typeof à l'aide de la directive ##.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              30 avril 2011 à 16:59:04

                                                              Je ne connais pas typeof, mais je connais le préprocesseur. Comme le préprocesseur passe avant toute étape de compilation etc. il en résultera que tu auras typeof(machin) et non le type de machin. Je suppose qu'il agit au même titre que sizeof. :)
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              La POO et le C

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown