Des arguments de variables en C, comment faire pour obtenir les valeurs d'un type générique?
Je suis en train d'utiliser C stdarg.h lib, avec un type générique.
Le type int, c'est mon type générique > pour le comprendre, s'il vous plaît, maintenez la lecture.
Donc, mon problème est:
J'ai une fonction qui accepte un nombre variable d'arguments. comme
void function (int paramN, ...);
Dans mon programme, il n'y a aucun moyen de savoir, qui est le type de la variable d'arguments, il peut être un char, un tableau, un int, un court, un point de fonction, etc... comme
function (paramN, "Hey, I'm a string", 1, function_pint, array, -1); //-1 is a sentinel.
Donc, je pense que, un int, est 32bits, dans un x86(32bits) du système, il en sera ainsi, toutes les adresses de la mémoire. Donc, si je reçois tous les arguments avec un int, il ne sera pas un problème, par exemple, "Hé, je suis une chaîne de" l'adresse de cette chaîne, l'ajustement, normalement, dans un 32bits variable, donc, il me suffit de faire un casting.
Im droit?
Puis-je le faire?
Note: je ne veux pas faire ma fonction comme printf (cette solution, ne rentrent pas dans ce cas, ok?)
Merci pour toute réponse.
Et désolé pour mon mauvais anglais.
OriginalL'auteur drigoSkalWalker | 2009-11-06
Vous devez vous connecter pour publier un commentaire.
Vous ne pouvez pas le faire de la manière que vous décrivez.
La convention d'appel C est pour les appelant à mettre les arguments sur la pile, mais il ne met pas d'informations sur les types, de sorte que le destinataire de l'appel doit avoir un moyen de trouver (au moins la taille de variables).
Pas de problème pour les fonctions avec des prototypes de chaque type est connu.
Avec des fonctions avec un nombre variable ou des paramètres (variadic) c'est plus délicat, il faut appeler va_arg pour chaque argument de lire chaque variable et vous devez fournir le type de va_arg. Si vous fournissez un type qui n'est pas le réel, le compilateur ne pas se plaindre (il peut pas il est temps de fonctionnement), mais tout peut arriver (généralement quelque chose de mal).
Donc vous ont pour passer le type.
Dans certains cas, vous pouvez prédire le type (par exemple: un compteur suivie par des entiers, et ainsi de suite), mais en général, vous passer codé dans les paramètres. Vous pouvez la passer encodé dans un format de chaîne comme printf, l'union astuce décrite par jldupont est également assez commun.
Mais de toute façon vous avez à passer.
Vous ne pouvez pas vraiment compter sur les données sous-jacentes représentation binaire, même pas la taille des données. Même si le programme semble fonctionner lorsque vous l'écrivez, il n'a pas de compatibilité et peut se casser à tout changement dans le système, de le compilateur, ou même lors de la modification des options de compilation.
Allons-y avec un exemple où vous passez le type, suivie de l'argument (donc ni l'union truc, ni la chaîne de format comme le printf). Ce qu'il fait est la conversion de tous, il est passé de la valeur à double et les ajouter, pas vraiment utile, n'est-ce pas:
Cet exemple utiliser le nouveau stdarg variadic en-tête défini en C99. Pour l'utiliser, vous devez disposer d'au moins un paramètre fixe à votre fonction (dans cet exemple c'est
count
). La bonne chose si que vous pouvez ainsi avoir plusieurs variadic listes dans votre fonction (c'est à dire quelque chose commemyfunc(int count1, ..., int count2, ...)
). La mauvaise chose est que vous ne pouvez pas purement variadic fonction (c'est à dire quelque chose comme mafonction(...) comme avec le vieux format. Vous pouvez toujours utiliser l'ancien format à l'aide de varargs compatibilité des en-têtes. Mais il est plus complexe et rarement nécessaire, car vous avez besoin de types, mais aussi d'une certaine façon pour connaître la liste est fini et quelque chose comme le comte est à portée de main (mais pas la seule façon de le faire, un "terminator" pourrait être utilisé par exemple).Woww, merci kriss, vous êtes un expert, merci pour votre temps, la réponse est génial! thankx beaucoup ;D
OriginalL'auteur kriss
Utiliser un void * (ou un typée structure) pour chaque paramètre & utiliser une structure avec un "type" argument (un entier). Un pointeur /union pour contenir la valeur réelle.
En d'autres termes, chaque paramètre est passé avec un pointeur typé structure. Chaque instance de cette tapé structure contient une valeur. Le type de cette "valeur" est contenue dans ce tapé structure.
Meilleur Exemple:
void function(Param *p1, Param *p2, ...)
Le dernier exemple de ce genre de truc que j'ai rencontré était DBus.
vous êtes correct.
OriginalL'auteur jldupont
Vous ne pouvez pas faire cela avec des arguments de variables de la façon dont vous décrivez car aucune information sur le type des arguments que vous avez pass est conservé après la compilation, à moins que vous ne explicitement. Même en passant l'adresse de l'argument variable ne vais pas vous dire cela, parce que les bits de la mémoire qui représentent une chaîne pourrait représenter un nombre ou quelque chose d'autre.
De faire des varargs travailler avec les types de variables, vous pouvez stocker des informations de type dans les arguments eux-mêmes (par exemple, comme décrit par jldupont dans sa réponse), ou vous pouvez enregistrer les informations dans un non-argument variable (par exemple, une chaîne de format comme
printf
's).Je comprends. Je suis juste essayer de faire clair pourquoi d'autres personnes choisissent cette solution que vous rejetez.
Ok Nathan, merci pour votre réponse, j'ai seulement besoin de trouver d'autres pour ce faire, ok? de toute façon, merci pour votre réponse les gars! ;D
OriginalL'auteur Nathan Kitchen
D'adaptation de http://en.wikipedia.org/wiki/Stdarg.h:
Qui est votre fonction ne peut pas sais simplement à partir de la arguments qui arguments sont des chaînes de caractères. Vous besoin de dire à votre fonction de ce à quoi s'attendre en quelque sorte. C'est pourquoi le
printf
convention est tellement commun.Nous avons compris que. Il est aucun moyen facile d'accomplir ce que vous avez demandé. Vous trouver un moyen de raconter une varags fonction de ce type de données est dans les arguments. Le
printf
convention n'est pas le seul choix (voir le lien ou jldupont de réponse), mais vous avez toujours à dire.Ok dmckee, merci pour votre réponse, j'ai seulement besoin de trouver d'autres pour ce faire, ok? de toute façon, merci pour votre réponse les gars! ;D
OriginalL'auteur dmckee
Essayer de u?intptr_t, qui est définie dans stdint.h. C'est un entier qui est garanti pour être assez grand pour contenir un pointeur.
Vous pouvez aussi envie de penser à ce qui se passe quand vous passer d'un nombre à virgule flottante; il est converti et a adopté une double. Si votre programme est en attente d'une int cela va détruire son point de vue de la pile. Ouch. Et le compilateur ne peut pas l'attraper.
Et votre fonction, tel que défini, a (interdiction des bits de codage dans paramN, auquel cas il devrait être un enum ou champ de bits, ou, au moins, non signé) aucun moyen de savoir quel est le type de paramètres qu'il reçoit, et en tant que tel est peu probable d'être en mesure de faire quelque chose d'utile avec eux. C n'a pas de type à l'exécution d'informations sur ses objets.
Ce qui, exactement, essayez-vous de faire?
Votre programme doit savoir ce que le type de chaque argument est, et la seule façon de savoir ce dans votre fonction est en quelque sorte à transmettre ces informations par le biais de vos arguments. Si vous appelez printf comme printf("%s:%d","string",i) il utilise son premier argument est une chaîne de caractères et la seconde comme un int, car la chaîne de format dit de le faire. Si l'utilisateur passe à autre chose, comme printf("%s:%d",0,"x") printf ne pouvez pas le savoir, et votre programme est dans l'erreur. Comment êtes-vous dire à vos fonctions comment utiliser ses arguments? Comment sait-il quels sont ceux qui sont entiers, qui sont des chaînes de caractères, qui sont des pointeurs, &c?
OriginalL'auteur Tim Schaeffer