J’ai un programme et je ne peux pas comprendre comment cela fonctionne. En voici une partie. Je ne comprends pas la ligne typedef void *COMPLEX
, la commande this
et la raison pour laquelle la struct COMPLEX_IMPL
est utilisée.
#ifndef _COMPLEX_H #define _COMPLEX_H typedef void *COMPLEX; COMPLEX NewCOMPLEX (double a, double b ); void DeleteCOMPLEX(COMPLEX this ); double GetA (COMPLEX this ); double GetB (COMPLEX this ); COMPLEX AddComplex (COMPLEX c1, COMPLEX c2, COMPLEX res); COMPLEX MultComplex (COMPLEX c1, COMPLEX c2, COMPLEX res); #endif /* _COMPLEX_H */ #ifndef _COMPLEX_H #define _COMPLEX_H typedef void *COMPLEX; COMPLEX NewCOMPLEX (double a, double b ); void DeleteCOMPLEX(COMPLEX this ); double GetA (COMPLEX this ); double GetB (COMPLEX this ); COMPLEX AddComplex (COMPLEX c1, COMPLEX c2, COMPLEX res); COMPLEX MultComplex (COMPLEX c1, COMPLEX c2, COMPLEX res); #endif /* _COMPLEX_H */
#include #include "complex.h" struct COMPLEX_IMPL { double a; double b; }; double GetA(COMPLEX this) { struct COMPLEX_IMPL *this_impl = (struct COMPLEX_IMPL*)this; return this_impl->a; }
typedef
définit un nom pour un type. Alors
typedef void *COMPLEX; COMPLEX z;
est équivalent à
void *z;
Un type de pointeur indique normalement le type de données pointé par le pointeur. void *
est une exception: c’est un moyen d’avoir un pointeur sans dire quel est le type de la valeur qu’il pointe. Vous pouvez librement affecter n’importe quel type de pointeur à un pointeur void *
et inversement.
void *
pointeurs void *
sont normalement utilisés dans les fonctions de bibliothèque génériques qui doivent fonctionner avec des données de tout type. Par exemple, considérons la fonction de bibliothèque standard memcpy
:
void *memcpy(void *dest, const void *src, size_t n);
Vous transmettez à cette fonction un pointeur sur un object de n’importe quel type src
, un pointeur sur un autre object (qui est généralement, mais pas toujours, du même type) dest
et un nombre d’octets à copier. La fonction copie les octets, peu importe la signification des octets, il suffit donc de passer deux pointeurs vers un type non spécifié.
L’utilisation de void *
n’est pas une bonne ou une pratique courante en matière de programmation. Un nombre complexe est représenté comme sa partie réelle et sa partie imaginaire:
struct COMPLEX_IMPL { double a; double b; };
Une bibliothèque de nombres complexes typique en ferait le type COMPLEX
.
Le code que vous avez posté masque l’implémentation du type COMPLEX
. Le fait que les nombres complexes soient mis en œuvre en tant que structure contenant deux membres double
n’apparaît que dans complex.c
. Les utilisateurs de la bibliothèque voient seulement qu’un COMPLEX
est un pointeur sur quelque chose. C’est une forme d’ abstraction de données : masquer les détails de la représentation d’un type de données. Mais c’est mal fait: avec cette définition, tout pointeur sur n’importe quoi peut être assigné à un COMPLEX
. La méthode normale consiste à utiliser une structure incomplète , déclarée et visible, mais dont les membres ne sont pas spécifiés. Dans complex.h
, vous écririez:
struct COMPLEX_IMPL; typedef struct COMPLEX_IMPL *COMPLEX;
Ainsi, la seule façon de créer légalement un COMPLEX_IMPL
consiste à COMPLEX_IMPL
les fonctions fournies par complex.h
, mais une variable de type COMPLEX
est visiblement un pointeur sur la représentation d’un nombre complexe défini dans complex.c
.
Oh, et this
est un nom de variable ordinaire.
typedef void *COMPLEX;
fait de COMPLEX
un alias pour le type void *
. (C’est mal, d’ailleurs, puisque vous ne devriez pas utiliser un type de pointeur et un caractère void
désactivera la vérification de type.)
Il n’y a pas de “commande” this
, c’est juste le nom d’un argument.
La struct
est utilisée pour garder les membres a et b
ensemble. C’est à quoi servent les structures.
typedef void* COMPLEX
fait de ‘COMPLEX’ un alias pour le type de pointeur vide ‘void *’ Je pense qu’un tutoriel en C vous serait très utile ici.
typedef void *
utiliser pour définir les fonctions dans les dll utilisées par votre projet