J'essaie d'apprendre C et je suis déjà très confus.
Dans les langues de l'OOP, je suis utilisé, il existe une capacité de surcharge de la méthode, dans laquelle la même fonction pourrait avoir des types de paramètres différents et que l'appelait le plus approprié. . p>
maintenant en C, je sais que ce n'est pas le cas, donc je ne peux pas comprendre le problème suivant, comment PrintF () fonctionne. p>
Par exemple: P>
char chVar = 'A'; int intVar = 123; float flVar = 99.999; printf("%c - %i - %f \n",chVar, intVar, flVar); printf("%i - %f - %c \n",intVar, flVar, chVar); printf("%f - %c - %i \n",flVar, chVar, intVar);
3 Réponses :
interne, printf code> (au moins généralement) utilise des macros de STDARG.H. L'idée générale est (une version grandement élargie de) quelque chose comme ceci:
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int my_vfprintf(FILE *file, char const *fmt, va_list arg) {
int int_temp;
char char_temp;
char *string_temp;
char ch;
int length = 0;
char buffer[512];
while ( ch = *fmt++) {
if ( '%' == ch ) {
switch (ch = *fmt++) {
/* %% - print out a single % */
case '%':
fputc('%', file);
length++;
break;
/* %c: print out a character */
case 'c':
char_temp = va_arg(arg, int);
fputc(char_temp, file);
length++;
break;
/* %s: print out a string */
case 's':
string_temp = va_arg(arg, char *);
fputs(string_temp, file);
length += strlen(string_temp);
break;
/* %d: print out an int */
case 'd':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 10);
fputs(buffer, file);
length += strlen(buffer);
break;
/* %x: print out an int in hex */
case 'x':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 16);
fputs(buffer, file);
length += strlen(buffer);
break;
}
}
else {
putc(ch, file);
length++;
}
}
return length;
}
int my_printf(char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(stdout, fmt, arg);
va_end(arg);
return length;
}
int my_fprintf(FILE *file, char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(file, fmt, arg);
va_end(arg);
return length;
}
#ifdef TEST
int main() {
my_printf("%s", "Some string");
return 0;
}
#endif
@Heathhunnicutt: Vous pourriez peut-être expliquer ce que vous pensez être faux?
Vous avez sauté à la partie où une liste Va_List a déjà été créée. Ce n'est pas automatique, mais votre réponse le ferait sembler. Cela peut être (probablement pas, mais possible que je vous accordais), que PrintF () est un wrapper autour de My_VPrintf () comme vous avez donné l'exemple. Mais la connaissance importante consiste à créer une VA_List, à l'aide de VA_START et de l'argument final non variable. Sauter cette partie est une non-réponse sur l'ordre de "faux".
@Heathhunnicutt: Je n'ai pas "sauter" quelque chose du genre. Si vous regardez plus avant le code, vous trouverez le my_printf code> et
my_fprintf code>, qui effectuent les appels le
va_start code> et
va_end < / code>.
@Heathhunnicutt: Je faisais assez d'une édition d'édition que vous devriez être capable de désactiver le bowvote.
(N'oubliez pas que si vous utilisez GCC (et g ++?), vous pouvez passer Quelqu'un pourrait-il ici expliquer comment C effectue la tâche ci-dessus? P>
blockQuote>
foi aveugle. Il suppose que vous avez assuré que les types des arguments correspondent parfaitement aux lettres correspondantes de votre chaîne de format. Lorsque maintenant peut-être que vous avez réellement passé un Si fondamentalement, si les types ne correspondent pas parfaitement, vous obtiendrez des données gravement brouillées. Et si vous êtes malchanceux, vous aurez un comportement indéfini. P> -wformat code> dans les options du compilateur pour obtenir le compilateur de vérifier que les types d'arguments correspondre au formatage. J'espère que d'autres compilateurs ont des options similaires.) P>
printf code> est appelé, tous les arguments sont représentés en binaire, non cérémoniblement concaténés ensemble et transmis efficacement comme un seul gros argument sur
printf code>. S'ils ne correspondent pas, vous aurez des problèmes. Comme
printf code> iTère via la chaîne de format, chaque fois qu'il se trouve
% d code> Il prendra 4 octets des arguments (en supposant 32 bits, ce serait 8 octets pour 64- Bit Ints bien sûr) et il les interprétera comme un entier. P>
double code> (prenant généralement deux fois plus de mémoire qu'un
int code>), auquel cas
printf code> sera juste Prenez 32 de ces bits et leur représentaient comme un entier. Ensuite, le champ Format suivant (peut-être un
% d code>) prendra le reste du double. P>
C prend en charge un type de signature de fonction appelé "Varargs" Signification "variable (nombre d'arguments)". Une telle fonction doit avoir au moins un argument requis. Dans le cas de Généralement, sur une machine à base de pile, lorsque vous appelez une fonction C, les arguments sont poussés sur la pile de droite à gauche. De cette manière, le premier argument à la fonction est celui trouvé sur le "sommet" de la pile, juste après l'adresse de retour. P> Il y a des macros définies qui vous permettent de récupérer les arguments variables. < / p> Les points de clé sont les suivants: p> J'ai posté une tonne de code que vous trouverez peut-être intéressant sur la question connexe: p> meilleure façon de stocker une VA_List pour une utilisation ultérieure à C / C ++ P> Voici un squelette d'un printf code>, la chaîne de format est un argument requis.
printf () code>, si la chaîne de format est fausse, le code lira des résultats non valides de la mémoire, éventuellement casque. Li>
va_start code>, incrémenté avec
VA_ARG code> et publié avec
VA_END code>. LI>.
ul>
printf () code> qui ne formule que des entiers ("% d"):
p>
Si vous voulez en savoir plus, lisez sur les conventions d'appel et la pile
Votre question concerne C, mais vous dites "J'essaie d'apprendre C ++." Si vous essayez d'apprendre C ++, il est préférable de commencer en évitant les parties C de la langue (et restez aux niveaux plus élevés d'abstraction que c ++ offre), puis une fois que vous êtes à l'aise avec cela, de creuser dans d'autres parties de la langue. .
Si vous ne voulez pas avoir à vous inquiéter de cela, passez
-wformat code> comme argument à g ++. Je pense que d'autres compilateurs devraient, je pense / espère / attendre, ont des avertissements similaires. Cela fera vérifier que le compilateur vérifie que les types correspondent.
Dupliqué possible de Définitions de fonction C / C ++ sans assemblage