Comment faire une fonction générique en utilisant void * dans c?
J'ai un incr
fonction d'incrémenter la valeur par 1
Je veux qu'il soit générique,parce que je ne veux pas faire de différentes fonctions pour la même fonctionnalité.
Supposons que je veux incrémenter int
,float
,char
par 1
void incr(void *vp)
{
(*vp)++;
}
Mais le problème je sais, c'est Dereferencing a void pointer is undefined behaviour
. Parfois, Il peut donner d'erreur :Invalid use of void expression
.
Mon main
d'une fonction est :
int main()
{
int i=5;
float f=5.6f;
char c='a';
incr(&i);
incr(&f);
incr(&c);
return 0;
}
Le problème est de savoir comment résoudre ce problème ? Est-il un moyen de le résoudre dans C
seulement
ou
vais-je avoir à définir incr()
pour chacun des types de données ? si oui, alors quelle est l'utilité de void *
Même problème avec le swap()
et sort()
.Je veux échanger et de trier tous les types de types de données avec la même fonction.
source d'informationauteur Omkant
Vous devez vous connecter pour publier un commentaire.
Vous pouvez mettre en œuvre la première comme une macro:
Bien sûr, cela peut avoir des effets secondaires désagréables si vous ne faites pas attention. Il s'agit de la seule méthode C, pour la même opération pour toute une variété de types. En particulier, depuis la macro est mis en œuvre à l'aide du texte de substitution, le temps que le compilateur voit, il vous suffit de le littéral code
++whatever;
et elle peut s'appliquer à++
correctement pour le type d'élément que vous avez fournis. Avec un pointeur sur void, vous ne savez pas beaucoup (le cas échéant) sur le type réel, de sorte que vous ne pouvez pas faire beaucoup de manipulation directe sur les données).void *
est normalement utilisée lorsque la fonction en question n'a pas vraiment besoin de connaître le type exact des données en cause. Dans certains cas (par exemple,qsort
), il utilise une fonction de rappel pour éviter d'avoir à connaître tous les détails des données.Depuis qu'il fait à la fois de tri et de swap, regardons qsort un peu plus en détail. Sa signature est:
Donc, la première est la
void *
vous m'avez demandé -- un pointeur vers les données à trier. Le second raconte qsort le nombre d'éléments dans le tableau. La troisième, la taille de chaque élément dans le tableau. Le dernier est un pointeur vers une fonction qui permet de comparer des éléments individuels, de sorteqsort
n'a pas besoin de savoir comment le faire. Par exemple, quelque part à l'intérieur de qsort sera un peu de code quelque chose comme:De même, pour échanger deux éléments, il va normalement avoir un tableau pour le stockage temporaire. Il va ensuite copier les octets de
array[i]
à son temp, puis à partir dearray[j]
àarray[i]
et enfin à partir detemp
àarray[j]
:À l'aide de
void *
ne vous donnera pas le comportement polymorphique, qui est ce que je pense que vous êtes la recherche pour.void *
simplement permet de contourner la vérification de type de tas de variables. Pour atteindre réel le comportement polymorphique, vous aurez à passer dans le type d'information comme une autre variable et les vérifier dans votreincr
fonction, puis le casting du pointeur vers le type désiré, OU par la transmission de toutes les opérations sur vos données comme des pointeurs de fonction (d'autres l'ont mentionnéqsort
comme un exemple). C automatiques ne sont pas polymorphisme intégré à la langue, de sorte qu'il serait à vous de le simuler. En coulisses, les langues qui construisent dans polymorphisme sont en train de faire quelque chose juste comme ça derrière les coulisses.D'élaborer, de
void *
est un pointeur vers un générique bloc de mémoire, ce qui pourrait être n'importe quoi: un int, float, string, etc. La longueur du bloc de mémoire n'est même pas stockées dans le pointeur, a fortiori, le type de données. Rappelez-vous que, en interne, toutes les données sont des bits et des octets, et les types sont vraiment juste des marqueurs pour comment la logique de données sont physiquement codé, car intrinsèquement, les bits et les octets sont sans type. En C, cette information n'est pas stockée avec des variables, de sorte que vous devez fournir pour le compilateur vous-même, de sorte qu'il sait si à appliquer les opérations de traiter les séquences de bits comme complément de 2 entiers, IEEE 754 double précision en virgule flottante de caractères ASCII des données, des fonctions, etc.; ce sont tous des normes spécifiques sur les formats et les opérations pour les différents types de données. Lorsque vous lancez unvoid *
à un pointeur sur un type spécifique, vous que le programmeur sont en affirmant que les données souligné est en fait le type que vous êtes un moulage. Sinon, vous êtes probablement dans le comportement bizarre.Donc, qu'est-ce que
void *
? C'est bon pour traiter les blocs de données sans égard au type. Cela est nécessaire pour des choses comme l'allocation de mémoire, la copie, les opérations de fichier, et le passage de pointeurs de fonctions. Dans presque tous les cas cependant, un programmeur C résumés de ce faible niveau de représentation, autant que possible, par la structuration de leurs données avec des types qui ont intégré dans les activités d'exploitation; ou à l'aide de structures, avec des opérations sur ces structures définies par le programmeur comme des fonctions.Vous pouvez découvrez l'explication Wikipedia pour plus d'info.
Vous ne pouvez pas faire exactement ce que vous demandez - opérateurs comme incrément besoin de travailler avec un type spécifique. Donc, vous pourrait faire quelque chose comme ceci:
Alors il faudrait l'appeler comme:
Bien sûr, ce n'est pas vraiment vous donner quelque chose de plus juste définition distincte
incr_int()
incr_float()
etincr_char()
fonctions - ce n'est pas le but de lavoid *
.Le but de
void *
est réalisée que lorsque l'algorithme que vous avez écrit n'est pas le type réel de l'objet. Un bon exemple est le standard de la fonction de triqsort()
qui est déclarée comme:Ceci peut être utilisé pour trier des tableaux de n'importe quel type d'objet - l'appelant a juste besoin de fournir une fonction de comparaison qui permet de comparer deux objets.
À la fois votre
swap()
etsort()
fonctions entrent dans cette catégorie.swap()
est encore plus facile - l'algorithme n'a pas besoin de savoir autre chose que de la taille des objets à échanger:Maintenant, compte tenu de tout réseau, vous pouvez échanger les deux éléments dans ce tableau:
Exemple pour l'utilisation de "Générique" de swap.
Ce code swaps de deux blocs de mémoire.
Et vous l'appeler comme ceci:
Je pense que cela devrait vous donner une idée de comment utiliser une fonction pour différents types de données.
Vous devriez jeter votre pointeur de type de béton avant d'être déréférencé. Donc, vous devriez également ajouter du code pour passer quel est le type de pointeur de variable.
Désolé si cela peut venir comme une non-réponse à cette vaste question "Comment faire de la fonction générique à l'aide de void * en c?".. mais les problèmes que vous semblez avoir (incrémentation d'une variable d'un type arbitraire, et d'échanger sur les 2 variables de types inconnus) peut être beaucoup plus facile avec des macros que les fonctions et les pointeurs nuls.
L'incrémentation est assez simple:
Pour un échange, je ferais quelque chose comme ceci:
...qui travaille pour ints, des doubles et des pointeurs de char (chaînes de caractères), d'après mes tests.
Tandis que l'incrémentation de la macro devrait être assez fort, la macro d'échange repose sur la
typeof()
opérateur, qui est un GCC/clang extension, ne fait PAS partie de la norme C (tho si vous ne vraiment jamais compiler avec gcc ou clang, cela ne devrait pas être trop un problème).Je sais que ce genre de esquivé la question d'origine; mais, je l'espère encore pour résoudre vos problèmes originaux.
Vous pouvez utiliser le type générique installations (C11 standard). Si vous avez l'intention d'utiliser plus avancés des fonctions mathématiques (plus avancé que la
++
opérateur), vous pouvez aller à<tgmath.h>
qui est de type générique définitions de fonctions dans<math.h>
et<complex.h>
.Vous pouvez également utiliser le
_Generic
mot clé pour définir un type générique de la fonction macro. Ci-dessous un exemple:Vous pouvez trouver plus d'informations sur le la langue standard et plus soffisticated exemples dans ce post de Rob programmation du blog.
Comme pour le
* void
d'échanger et de tri des questions, mieux de se référer à Jerry Cercueil's réponse.