Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Défis]#11 : zPrintf

    19 mai 2012 à 19:54:43

    Yop,

    Voici ma participation pour le niveau 3. Mon code est encore assez brouillon et ne gère pas les formats "%e" et "%g". Il gère par contre l'affichage des flottants (avec la possibilité de spécifier le nombre souhaité de chiffre après la virgule) et ce, peut importe leur taille. Cependant, étant donné que je converti les nombres flottants en base 10, les valeurs affichées peuvent être imprécises (et cela ce remarque d'autant plus que le nombre est grand ou petit) :


    #include <float.h>
    #include <limits.h>
    #include <math.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    
    static double zmodf(double, double *);
    static int print_double(double, unsigned);
    static int print_int(size_t, unsigned);
    static int print_str(char const *);
    static int conversion(char const *, va_list *, int *);
    
    
    static double
    zmodf(double n, double *pi)
    {
    	double i = 0.;
    	double tmp = n;
    	double exp;
    	int digit;
    
    	if (n < 1.) {
    		*pi = i;
    		return n;
    	}
    
    	for (exp = 0.; tmp >= FLT_RADIX; exp += 1.)
    		tmp /= FLT_RADIX;
    
    	exp = pow(FLT_RADIX, exp);
    	digit = 0;
    
    	do {
    		i += (int)tmp * exp;
    		tmp -= (int)tmp;
    		tmp *= FLT_RADIX;
    		exp /= FLT_RADIX;
    	} while (exp >= 1. && digit++ < DBL_MANT_DIG);
    
    	*pi = i;
    	return n - i;
    }
    
    
    static int
    print_double(double n, unsigned precision)
    {
    	double i, f;
    	int exp;
    	int nb = 0;
    
    	if (n < 0.) {
    		putchar('-');
    		n = -n;
    		++nb;
    	}
    
    	f = zmodf(n, &i);
    	exp = (int)log10(i);
    	i /= pow(10., (double)exp);
    
    	while (i > 0. && exp-- >= 0) {
    		putchar((int)i + '0');
    		i -= (int)i;
    		i *= 10.;
    		++nb;
    	}
    
    	if (precision) {
    		putchar('.');
    		++nb;
    	}
    
    	while (precision-- > 0) {
    		f *= 10.;
    		putchar((int)f + '0');
    		f -= (int)f;
    		++nb;
    	}
    
    	return nb;
    }
    
    
    static int
    print_int(size_t n, unsigned base)
    {
    	static char buffer[sizeof (long) * CHAR_BIT];
    	char *s = buffer;
    	int nb = 0;
    
    	if (n == 0) {
    		putchar('0');
    		return 1;
    	}
    
    	while (n != 0) {
    		*s++ = "0123456789ABCDEF"[n % base];
    		n /= base;
    	}
    
    	do {
    		putchar(*--s);
    		++nb;
    	} while (s != buffer);
    
    	return nb;
    }
    
    
    static int
    print_str(char const *s)
    {
    	int nb;
    
    	for (nb = 0; s[nb] != '\0'; ++nb)
    		putchar(s[nb]);
    
    	return nb;
    }
    
    
    static int
    conversion(char const *fmt, va_list *ap, int *nb)
    {
    	char const *t = fmt;
    	unsigned precision = 6;
    	int large = 0;
    	unsigned base = 10;
    	long tmp;
    
    	for (;;) {
    		switch (*fmt) {
    		case '%' :
    			++fmt;
    			putchar('%');
    			++*nb;
    			goto conversion_end;
    
    		case '.' :
    			++fmt;
    			precision = (unsigned)strtoul(fmt, (char **)&fmt, 10);
    			break;
    
    		case 'f' :
    			++fmt;
    			*nb += print_double(va_arg(*ap, double), precision);
    			goto conversion_end;
    
    		case 'l' :
    			++fmt;
    			large = 1;
    			break;
    
    		case 'd' :
    		case 'i' :
    			++fmt;
    
    			if (large)
    				tmp = va_arg(*ap, long);
    			else
    				tmp = va_arg(*ap, int);
    
    			if (tmp < 0) {
    				putchar('-');
    				++*nb;
    				tmp = -tmp;
    			}
    
    			*nb += print_int((size_t)tmp, base);
    			goto conversion_end;
    
    		case 'x' :
    			base = 18;
    		case 'o' :
    			base -= 2;
    		case 'u' :
    			++fmt;
    
    			if (large)
    				*nb += print_int(va_arg(*ap, unsigned long), base);
    			else
    				*nb += print_int(va_arg(*ap, unsigned), base);
    			goto conversion_end;
    
    		case 's' :
    			++fmt;
    			*nb += print_str(va_arg(*ap, char const *));
    			goto conversion_end;
    
    		default :
    			++fmt;
    			goto conversion_end;
    		}
    	}
    
    conversion_end:
    	return (int)(fmt - t);
    }
    
    
    int
    zprintf(char const *fmt, ...)
    {
    	va_list ap;
    	int nb = 0;
    
    	va_start(ap, fmt);
    	while (*fmt != '\0') {
    		switch (*fmt) {
    		case '%' :
    			fmt += conversion(fmt + 1, &ap, &nb);
    			break;
    
    		default :
    			putchar(*fmt);
    			++nb;
    			break;
    		}
    
    		++fmt;
    	}
    
    	va_end(ap);
    	return nb;
    }
    
    
    int
    main(void)
    {
    	zprintf("%% %f %s %ld\n", 6789.54467, "pouf !", 6789089L);
    	return 0;
    }
    



    À noter que je n'ai pas recoder toutes les fonctions de la bibliothèque standard dont j'avais besoin, mise à part modf (l'exercice était intéressant :) ).
    • Partager sur Facebook
    • Partager sur Twitter
      19 mai 2012 à 22:23:19

      Juste un truc, est-ce que l'exo autorise ça ?

      zprintf("%lllllllllllld\n", 6789089L);
      


      Moi je suis parti sur un truc vraiment 'printf'. ^^
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        20 mai 2012 à 0:00:12

        @Taurre : ton code est plutôt bien, j'ai juste relevé une petite coquille pour %x :

        case 'x' :
        base = 18;
        


        C'est pas la base 16 plutôt ? Sinon j'étudierai ton code plus en profondeur demain. :)

        @Pouet : je ne sais pas, je dosi t'avouer que tu me pose une colle. Que fait printf dans ce cas ?
        • Partager sur Facebook
        • Partager sur Twitter
          20 mai 2012 à 0:03:41

          Citation

          If a conversion specification is invalid, the behavior is undefined.


          Mais je pense que gérer les cas de formateurs indéfinis peut être intéressant dans le cas de l'exo. :)
          Au moins afficher un message d'erreur comme quoi le formateur est indéfini et que la conversion ne peut pas continuer. :)
          Bon, il faudrait faire ça au niveau du compilateur et pas en runtime, mais nous on peut rien y faire. ^^ On se contente de ce qu'on est en mesure de faire. :D
          • Partager sur Facebook
          • Partager sur Twitter
            20 mai 2012 à 10:34:18

            Citation : informaticienzero

            @Taurre : ton code est plutôt bien, j'ai juste relevé une petite coquille pour %x :

            case 'x' :
            base = 18;
            



            C'est pas la base 16 plutôt ?



            Pour le coup il a rusé : le déroulement du programme continue dans le branchement 'o' (vu qu'il n'y a pas de branchements inconditionnels) et soustrait 2 à cette valeur.
            • Partager sur Facebook
            • Partager sur Twitter
            Staff désormais retraité.
              20 mai 2012 à 12:04:40

              Citation : Lucas-84


              Citation : informaticienzero

              @Taurre : ton code est plutôt bien, j'ai juste relevé une petite coquille pour %x :

              case 'x' :
              base = 18;
              



              C'est pas la base 16 plutôt ?



              Pour le coup il a rusé : le déroulement du programme continue dans le branchement 'o' (vu qu'il n'y a pas de branchements inconditionnels) et soustrait 2 à cette valeur.



              Exact :)
              Cela m'évite de répéter le code du format "%u" pour les formats "%o" et "%x" ;)
              • Partager sur Facebook
              • Partager sur Twitter
                20 mai 2012 à 12:14:21

                Rien à voir avec le sujet, mais pour la culture générale :

                Citation : Mr21

                D'ailleurs je n'avais pas remarque mais gcc donne des warnings pour printf, c'est la seule fonction qui est favoriser comme ça ou pas?


                Voir __attribute__((format(printf,m,n))), extension GCC (idem pour scanf()). Si tu écris une fonction qui utilises printf() en interne, n'hésite pas à t'en servir, ta fonction aura aussi le droit à ce traitement de faveur :)
                • Partager sur Facebook
                • Partager sur Twitter
                  25 mai 2012 à 18:00:37

                  Hé, je savais pas que l’exercice était posté !

                  Bon, du coup je finis mon code et je le poste.

                  Citation : entwanne

                  Citation : Taurre

                  ... J'avoue que j'ai bon y réfléchir je ne vois pour l'instant pas comment faire cela. Je serais curieux de savoir comment ils s'en sortent à Epitech par exemple :)


                  Pour parler franchement, la plupart des gens ne pensent pas à la manière dont cela est stocké, et vont partir de leur postulat que c'est en base 10, et donc l'afficher à base de multiplications successives par 10.
                  Très peu se servent de la mantisse et de l'exponentiation pour écrire leur résultat.



                  C’est ce que je me disais, on pourrait se contenter d’afficher la partie entière (obtenue avec une conversion en entier) avec la fonction pour afficher des entiers, puis afficher la partie décimale par multiplications successives de la base. En faisant gaffe à l’exposant quand même.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    26 mai 2012 à 13:27:18

                    Pour les flottants, récupérer tout ça à base de multiplications/divisions successives donne un bon résultat ?
                    Jouer avec la mantisse et compagnie, je l'ai déjà fait, c'est assez reulou, pas envie de recommencer. :lol:
                    • Partager sur Facebook
                    • Partager sur Twitter
                      26 mai 2012 à 16:36:02

                      Hey,

                      Après moulte sueurs, mon code pour le niveau 2.

                      #include <stdio.h>
                      #include <stdarg.h>
                      #include "printf.h"
                      
                      #define PUTC(c, dst) \
                          do { \
                              if (genericputc((c), (dst)) == RET_FAIL) \
                                  return RET_FAIL; \
                          } while (0)
                      
                      #define PRINT(x, c, dst) \
                          while ((x)) \
                              PUTC((c), (dst));
                      
                      #define isdigit(c) \
                          ((c) >= '0' && (c) <= '9')
                      
                      typedef enum {
                          RET_FAIL = -1,
                          RET_OK = 1
                      } funcret;
                      
                      typedef enum {
                          F_DUMMY = -1,
                          F_ZEROPADDED = 1 << 0,
                          F_SHOWSIGN = 1 << 1,
                          F_NEGATIVE = 1 << 2,
                          F_SPACE = 1 << 3,
                          F_LEFTADJUSTED = 1 << 4,
                          F_ALTERNATE = 1 << 5,
                          F_UPCASE = 1 << 6,
                          F_ZEROTRUNC = 1 << 7,
                          F_SIGNED = 1 << 8
                      } flags;
                      
                      typedef enum {
                          Q_NO = '\0',
                          Q_LARGE = 'l',
                          Q_SHORT = 'h'
                      } qualifier;
                      
                      typedef struct {
                          char *p;
                          size_t i;
                          size_t max;
                      } string;
                      
                      typedef struct {
                          enum {
                              TYPE_STRING,
                              TYPE_FILE
                          } type;
                      
                          union {
                              FILE *fp;
                              string s;
                          } fs;
                      } contents;
                      
                      typedef struct {
                          contents *dst;
                      
                          union {
                              unsigned long u;
                              long n;
                              const char *s;
                              void *p;
                          } data;
                      
                          enum {
                              BASE_OCT = 8,
                              BASE_DEC = 10,
                              BASE_HEXA = 16
                          } b;
                      
                          int field;
                          int prec;
                          flags f;
                      
                          enum {
                              SIGN_PLUS = '+',
                              SIGN_MINUS = '-',
                              SIGN_SPACE = ' ',
                              SIGN_NO = '\0'
                          } s;
                      
                          qualifier q;
                      } conf;
                      
                      static int writed = 0;
                      
                      static int 
                      printcharacter(int c, FILE *fp) {
                          return putc(c, fp) == EOF ? RET_FAIL : RET_OK;
                      }
                      
                      static int
                      fillstring(int c, string *s) {
                          if (s->max == (size_t)-1 || s->i < s->max - 1)
                              s->p[s->i++] = (char)c;
                      
                          return RET_OK;
                      }
                      
                      static int
                      genericputc(int c, contents *dst) {
                          int ret;
                      
                          if (dst->type == TYPE_STRING)
                              ret = fillstring(c, &dst->fs.s);
                          else
                              ret = printcharacter(c, dst->fs.fp);
                      
                          if (ret != RET_FAIL)
                              ++writed;
                      
                          return ret;
                      }
                      
                      static int 
                      printinteger(conf *c) {
                          char buf[64];
                          char const * const alphabet = c->f & F_UPCASE ?
                              "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
                              "0123456789abcdefghijklmnopqrstuvwxyz";
                          int i = 0;
                      
                          if (c->f & F_LEFTADJUSTED)
                              c->f &= ~F_ZEROPADDED;
                      
                          if (c->f & F_ALTERNATE) {
                              if (c->b == BASE_OCT) {
                                  --c->field;
                                  --c->prec;
                              }
                              else if (c->b == BASE_HEXA)
                                  c->field -= 2;
                          }
                      
                          if (c->data.u == 0)
                              buf[i++] = '0';
                      
                          while (c->data.u != 0) {
                              buf[i++] = alphabet[c->data.u % c->b];
                              c->data.u /= c->b;
                          }
                      
                          c->prec = c->prec < 0 ? 0 : c->prec;
                          c->prec = i > c->prec ? i : c->prec;
                          c->field -= c->prec;
                      
                          if (!(c->f & F_LEFTADJUSTED))
                              PRINT(c->field-- > 0, ' ', c->dst);
                      
                          if (c->f & F_ALTERNATE) {
                              if (c->b == BASE_OCT)
                                  PUTC('0', c->dst);
                              else if (c->b == BASE_HEXA) {
                                  PUTC('0', c->dst);
                                  PUTC(alphabet[33], c->dst);
                              }
                          }
                      
                          if (c->s != SIGN_NO)
                              PUTC(c->s, c->dst);
                      
                          if (!(c->f & F_LEFTADJUSTED))
                              PRINT(c->field-- > 0, c->f & F_ZEROPADDED ? '0' : ' ', c->dst);
                      
                          PRINT(c->prec-- > i, '0', c->dst);
                          PRINT(i-- > 0, buf[i], c->dst);
                          PRINT(c->field-- > 0, ' ', c->dst);
                      
                          return RET_OK;
                      }
                      
                      static int
                      printsigned(conf *c) {
                          if (c->data.n < 0) {
                              c->s = SIGN_MINUS;
                              c->data.u = (unsigned long)-c->data.n;
                          } 
                          else if (c->f & F_SHOWSIGN)
                              c->s = SIGN_PLUS;
                          else if (c->f & F_SPACE)
                              c->s = SIGN_SPACE;
                      
                          if (c->s != SIGN_NO)
                              --c->field;
                      
                          return printinteger(c);
                      }
                      
                      static int
                      printnumber(conf *c, va_list **ap) {
                          if (c->q == Q_LARGE) {
                              if (c->f & F_SIGNED)
                                  c->data.n = va_arg(**ap, long);
                              else
                                  c->data.u = va_arg(**ap, unsigned long);
                          }
                          else if (c->q == Q_SHORT) {
                              if (c->f & F_SIGNED)
                                  c->data.n = (short)va_arg(**ap, int);
                              else
                                  c->data.u = (unsigned short)va_arg(**ap, unsigned);
                          }
                          else if (c->f & F_SIGNED)
                              c->data.n = va_arg(**ap, int);
                          else
                              c->data.u = va_arg(**ap, unsigned);
                      
                          return c->f & F_SIGNED ? printsigned(c) : printinteger(c);
                      }
                      
                      static int
                      printstring(conf *c) {
                          int size = 0, i;
                      
                          if (c->data.s == NULL) {
                              c->data.s = "<null>";
                              size = 6;
                          }
                          else 
                              while (c->data.s[size] != '\0' && (unsigned)size < (unsigned)c->prec)
                                  ++size;
                      
                          if (!(c->f & F_LEFTADJUSTED))
                              PRINT(c->field-- > size, ' ', c->dst);
                      
                          for (i = 0; i < size; ++i)
                              PUTC(*c->data.s++, c->dst);
                      
                          PRINT(c->field-- > size, ' ', c->dst);
                      
                          return RET_OK;
                      }
                      
                      static int
                      printpointer(conf *c) {
                          unsigned long value = (unsigned long)c->data.p;
                      
                          if (c->field == 0) {
                              c->field = 2 * sizeof c->data.p;
                              c->f |= F_ZEROPADDED;
                          }
                      
                          c->f |= F_ALTERNATE;
                      
                          if (value != 0UL) {
                              c->b = BASE_HEXA;
                              c->data.u = value;
                              c->s = SIGN_NO;
                          }
                          else {
                              c->data.s = "(nil)";
                              c->prec = 5;
                          }
                      
                          return value == 0UL ? printstring(c) : printinteger(c);
                      }
                      
                      static int
                      initflags(const char ***fmt) {
                          flags f = 0;
                      
                          while (1) {
                              ++**fmt;
                      
                              switch (***fmt) {
                              case '-':
                                  f |= F_LEFTADJUSTED;
                                  break;
                              case '+':
                                  f |= F_SHOWSIGN;
                                  break;
                              case ' ':
                                  f |= F_SPACE;
                                  break;
                              case '#':
                                  f |= F_ALTERNATE;
                                  break;
                              case '0':
                                  f |= F_ZEROPADDED;
                                  break;
                              default:
                                  goto end;
                              }
                          }
                      
                        end:
                          return f;
                      }
                      
                      static int
                      getint(const char ***s) {
                          int i;
                      
                          for (i = 0; isdigit(***s); ++**s)
                              i = i * 10 + (***s - '0');
                      
                          return i;
                      }
                      
                      static int
                      initfield(const char ***fmt, flags *f, va_list **ap) {
                          int field = 0;
                      
                          if (***fmt == '*') {
                              ++**fmt;
                              field = va_arg(**ap, int);
                          } 
                          else if (isdigit(***fmt))
                              field = getint(fmt);
                      
                          if (field < 0) {
                              field *= -1;
                              *f |= F_LEFTADJUSTED;
                          }
                      
                          return field;
                      }
                      
                      static int
                      initprec(const char ***fmt, va_list **ap) {
                          int prec = -1;
                      
                          if (***fmt == '.') {
                              ++**fmt;
                      
                              if (***fmt == '*') {
                                  ++**fmt;
                                  prec = va_arg(**ap, int);
                              } 
                              else if (isdigit(***fmt))
                                  prec = getint(fmt);
                      
                              prec = prec < 0 ? 0 : prec;
                          }
                      
                          return prec;
                      }
                      
                      static qualifier
                      initqualifier(const char ***fmt) {
                          qualifier q = Q_NO;
                      
                          switch (***fmt) {
                          case 'h':
                          case 'l':
                              q = ***fmt;
                              ++**fmt;
                          }
                      
                          return q;
                      }
                      
                      static int
                      convert(contents *dst, const char **fmt, va_list *ap) {
                          conf c = {dst, {0}, BASE_DEC, 0, 0, 0, SIGN_NO, Q_NO};
                          int ret = RET_OK;
                      
                          if (**fmt != '%') {
                              PUTC(**fmt, c.dst);
                              goto end;
                          }
                      
                          c.f = initflags(&fmt);
                          c.field = initfield(&fmt, &c.f, &ap);
                          c.prec = initprec(&fmt, &ap);
                          c.q = initqualifier(&fmt);
                      
                          switch (**fmt) {
                          case 'c':
                              if (!(c.f & F_LEFTADJUSTED))
                                  PRINT(--c.field > 0, ' ', c.dst);
                      
                              PUTC(va_arg(*ap, int), c.dst);
                              PRINT(--c.field > 0, ' ', c.dst);
                              goto end;
                          case 's':
                              c.data.s = va_arg(*ap, char *);
                              ret = printstring(&c);
                              goto end;
                          case 'p':
                              c.data.p = va_arg(*ap, void *);
                              ret = printpointer(&c);
                              goto end;
                          case 'n':
                              if (c.q == Q_LARGE) {
                                  long *p = va_arg(*ap, long *);
                                  *p = writed;
                              } 
                              else {
                                  int *p = va_arg(*ap, int *);
                                  *p = writed;
                              }
                              goto end;
                          case 'o':
                              c.b = BASE_OCT;
                              break;
                          case 'X':
                              c.f |= F_UPCASE;
                          case 'x':
                              c.b = BASE_HEXA;
                              break;
                          case 'd': case 'i':
                              c.f |= F_SIGNED;
                          case 'u':
                              break;
                          default:
                              PUTC(**fmt, dst);
                              goto end;
                          }
                      
                          ret = printnumber(&c, &ap);
                      
                        end:
                          return ret;
                      }
                      
                      int
                      zprintf(const char *format, ...) {
                          va_list ap;
                          int ret;
                      
                          va_start(ap, format);
                          ret = zvfprintf(stdout, format, ap);
                          va_end(ap);
                      
                          return ret;
                      }
                      
                      int
                      zfprintf(FILE *stream, const char *format, ...) {
                          va_list ap;
                          int ret = 0;
                      
                          va_start(ap, format);
                          ret = zvfprintf(stream, format, ap);
                          va_end(ap);
                      
                          return ret;
                      }
                      
                      int
                      zsprintf(char *str, const char *format, ...) {
                          va_list ap;
                          int ret = 0;
                      
                          va_start(ap, format);
                          ret = zvsprintf(str, format, ap);
                          va_end(ap);
                      
                          return ret;
                      }
                      
                      int 
                      zsnprintf(char *str, size_t size, const char *format, ...) {
                          va_list ap;
                          int ret = 0;
                      
                          va_start(ap, format);
                          ret = zvsnprintf(str, size, format, ap);
                          va_end(ap);
                      
                          return ret;
                      }
                      
                      int 
                      zvprintf(const char *format, va_list ap) {
                          return zvfprintf(stdout, format, ap);
                      }
                      
                      int 
                      zvfprintf(FILE *stream, const char *format, va_list ap) {
                          contents dst;
                      
                          dst.type = TYPE_FILE;
                          dst.fs.fp = stream;
                      
                          for (; *format != '\0'; ++format)
                              if (convert(&dst, &format, &ap) == RET_FAIL)
                                  return -1;
                      
                          return writed;
                      }
                      
                      int
                      zvsprintf(char *str, const char *format, va_list ap) {
                          return zvsnprintf(str, -1UL, format, ap);
                      }
                      
                      int 
                      zvsnprintf(char *str, size_t size, const char *format, va_list ap) {
                          contents dst;
                      
                          dst.type = TYPE_STRING;
                          dst.fs.s.p = str;
                          dst.fs.s.i = 0UL;
                          dst.fs.s.max = size;
                      
                          for (; *format != '\0'; ++format)
                              if (convert(&dst, &format, &ap) == RET_FAIL)
                                  return -1;
                      
                          str[dst.fs.s.i] = '\0';
                      
                          return writed;
                      }
                      


                      C'est sûrement encore un nid à bogues, mais ça semble globalement marcher. Qu'en pensez-vous ?

                      Edit : Correction d'une bourde.
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Staff désormais retraité.
                        26 mai 2012 à 17:03:18

                        J'ai pas regardé ton code, mais il y a des erreurs. :)

                        line 182: Function call argument is an uninitialized value


                        #define mprintf(...) {  printf(": [%d]\n", printf(__VA_ARGS__));     \
                                                printf(": [%d]\n", zprintf(__VA_ARGS__)); }
                        
                        int main(void) {
                          unsigned int n = 0x1000;
                        //  unsigned int a = 0xABCDEF;
                        //  char b = 'a';
                          
                          mprintf("%20p", &n);
                          mprintf("%.0d %0.3d", 0, 10);
                          
                          mprintf ("Characters: %c %c ", 'a', 65);
                          mprintf ("Decimals: %d %ld", 1977, 650000L);
                          mprintf ("Preceding with blanks: %10d ", 1977);
                          mprintf ("Preceding with zeros: %010d ", 1977);
                          mprintf ("Some different radixes: %d %x %o %#x %#o ", 100, 100, 100, 100, 100);
                          mprintf ("floats: %4.2f %+.0e %E ", 3.1416, 3.1416, 3.1416);
                          mprintf ("Width trick: %*d ", 5, 10);
                          mprintf ("%s ", "A string");
                          
                          static wchar_t wstr[] = L"abcdefghijk";
                          
                          mprintf("|1234567890123|");
                          mprintf("|%13ls|", wstr);
                          mprintf("|%-13.9ls|", wstr);
                          mprintf("|%13.10ls|", wstr);
                          mprintf("|%13.11ls|", wstr);
                          mprintf("|%13.15ls|", &wstr[2]);
                          //mprintf("|%13lc|", (wint_t) wstr[5]);
                          
                        	fflush(stdout);
                          return EXIT_SUCCESS;
                        }
                        

                        .
                                  0xbffff384: [20]
                                  0xbffff384: [20]
                         010: [4]
                        0 010: [25]
                        Characters: a A : [16]
                        Characters: a A : [41]
                        Decimals: 1977 650000: [21]
                        Decimals: 1977 650000: [62]
                        Preceding with blanks:       1977 : [34]
                        Preceding with blanks:       1977 : [96]
                        Preceding with zeros: 0000001977 : [33]
                        Preceding with zeros:       1977 : [129]
                        Some different radixes: 100 64 144 0x64 0144 : [45]
                        Some different radixes: 100 64 144 0x64 0144 : [174]
                        floats: 3.14 +3e+00 3.141600E+00 : [33]
                        floats: f e E : [188]
                        Width trick:    10 : [19]
                        Width trick:    10 : [207]
                        A string : [9]
                        A string : [216]
                        |1234567890123|: [15]
                        |1234567890123|: [231]
                        |  abcdefghijk|: [15]
                        |            a|: [246]
                        |abcdefghi    |: [15]
                        |a            |: [261]
                        |   abcdefghij|: [15]
                        |            a|: [276]
                        |  abcdefghijk|: [15]
                        |            a|: [291]
                        |    cdefghijk|: [15]
                        |            c|: [306]


                        Edit: Ah, aussi, tu pourrais fournir un code compilable avec tout ce qui s'en suit... genre printf.h et un main valide histoire qu'on ai pas à se prendre la tête avec ces broutilles...

                        Quelqu'un pour répondre à ma question juste avant ? =D
                        • Partager sur Facebook
                        • Partager sur Twitter
                          26 mai 2012 à 17:15:15

                          Citation : Pouet_forever


                          Pour les flottants, récupérer tout ça à base de multiplications/divisions successives donne un bon résultat ?



                          À vue de nez, non. En tous les cas pas avec mon code :-°
                          Voilà ce qu'affiche printf et ma fonction pour un nombre de valeur FLT_MAX :

                          340282346638528859811704183484516925440.000000
                          340282346638528876425766611646395176649.000000


                          Bref, c'est pas top >_<

                          Citation : Pouet_forever


                          Jouer avec la mantisse et compagnie, je l'ai déjà fait, c'est assez reulou, pas envie de recommencer. :lol:



                          Tu as encore ton code ? Je serais curieux de voir comment être plus précis :)

                          Citation : Maëlan


                          C’est ce que je me disais, on pourrait se contenter d’afficher la partie entière (obtenue avec une conversion en entier) avec la fonction pour afficher des entiers, puis afficher la partie décimale par multiplications successives de la base. En faisant gaffe à l’exposant quand même.



                          La conversion en entier ne me paraît pas une bonne solution, même avec un long long on ne fait pas long feu (0x1.FFFFFEp127 au maximum pour un float selon la norme IEEE 754).
                          • Partager sur Facebook
                          • Partager sur Twitter
                            26 mai 2012 à 17:52:23

                            @Pouet :

                            - Pour le premier test (0 en précision), gcc m'affiche un warning. J'ai toutefois rajouté une condition pour gérer ce cas.
                            - Pour le quatrième test, j'avais oublié une condition.
                            - Sinon, pour les erreurs de taille, j'avais oublié de remettre la variable statique à zéro à chaque appel de printf.
                            - Par ailleurs, tu m'as fait pensé aux wchar_t que j'avais complètement zappé.

                            #include <stdio.h>
                            #include <stdarg.h>
                            #include "printf.h"
                            
                            #define testprintf(...) \
                                do { \
                                    printf(": [%d]\n", printf(__VA_ARGS__)); \
                                    printf(": [%d]\n", zprintf(__VA_ARGS__)); \
                                } while (0)
                            
                            int 
                            main(void) {
                                unsigned int n = 0x1000;
                                static char s[] = "abcdefghijk";
                            
                                testprintf("%20p", &n);
                                testprintf("%.0d %0.3d", 0, 10);
                                testprintf("Characters: %c %c ", 'a', 65);
                                testprintf("Decimals: %d %ld", 1977, 650000L);
                                testprintf("Preceding with blanks: %10d ", 1977);
                                testprintf("Preceding with zeros: %010d ", 1977);
                                testprintf("Some different radixes: %d %x %o %#x %#o ", 100, 100, 100, 100, 100);
                                testprintf("Width trick: %*d ", 5, 10);
                                testprintf("%s ", "A string");
                                testprintf("|1234567890123|");
                                testprintf("|%13s|", s);
                                testprintf("|%-13.9s|", s);
                                testprintf("|%13.10s|", s);
                                testprintf("|%13.11s|", s);
                                testprintf("|%13.15s|", &s[2]);
                            
                                fflush(stdout);
                                return 0;
                            }
                            


                            #include <stdio.h>
                            #include <stdarg.h>
                            #include <wchar.h>
                            #include "printf.h"
                            
                            #define PUTC(c, dst) \
                                do { \
                                    if (genericputc((c), (dst)) == RET_FAIL) \
                                        return RET_FAIL; \
                                } while (0)
                            
                            #define PRINT(x, c, dst) \
                                while ((x)) \
                                    PUTC((c), (dst));
                            
                            #define isdigit(c) \
                                ((c) >= '0' && (c) <= '9')
                            
                            typedef enum {
                                RET_FAIL = -1,
                                RET_OK = 1
                            } funcret;
                            
                            typedef enum {
                                F_DUMMY = -1,
                                F_ZEROPADDED = 1 << 0,
                                F_SHOWSIGN = 1 << 1,
                                F_NEGATIVE = 1 << 2,
                                F_SPACE = 1 << 3,
                                F_LEFTADJUSTED = 1 << 4,
                                F_ALTERNATE = 1 << 5,
                                F_UPCASE = 1 << 6,
                                F_ZEROTRUNC = 1 << 7,
                                F_SIGNED = 1 << 8
                            } flags;
                            
                            typedef enum {
                                Q_NO = '\0',
                                Q_LARGE = 'l',
                                Q_SHORT = 'h'
                            } qualifier;
                            
                            typedef struct {
                                char *p;
                                size_t i;
                                size_t max;
                            } string;
                            
                            typedef struct {
                                enum {
                                    TYPE_STRING,
                                    TYPE_FILE
                                } type;
                            
                                union {
                                    FILE *fp;
                                    string s;
                                } fs;
                            } contents;
                            
                            typedef struct {
                                contents *dst;
                            
                                union {
                                    unsigned long u;
                                    long n;
                                    const char *s;
                                    const wchar_t *ls;
                                    void *p;
                                } data;
                            
                                enum {
                                    BASE_OCT = 8,
                                    BASE_DEC = 10,
                                    BASE_HEXA = 16
                                } b;
                            
                                int field;
                                int prec;
                                flags f;
                            
                                enum {
                                    SIGN_PLUS = '+',
                                    SIGN_MINUS = '-',
                                    SIGN_SPACE = ' ',
                                    SIGN_NO = '\0'
                                } s;
                            
                                qualifier q;
                            } conf;
                            
                            static int writed = 0;
                            
                            static int 
                            printcharacter(int c, FILE *fp) {
                                return putc(c, fp) == EOF ? RET_FAIL : RET_OK;
                            }
                            
                            static int
                            fillstring(int c, string *s) {
                                if (s->max == (size_t)-1 || s->i < s->max - 1)
                                    s->p[s->i++] = (char)c;
                            
                                return RET_OK;
                            }
                            
                            static int
                            genericputc(int c, contents *dst) {
                                int ret;
                            
                                if (dst->type == TYPE_STRING)
                                    ret = fillstring(c, &dst->fs.s);
                                else
                                    ret = printcharacter(c, dst->fs.fp);
                            
                                if (ret != RET_FAIL)
                                    ++writed;
                            
                                return ret;
                            }
                            
                            static int 
                            printinteger(conf *c) {
                                char buf[64];
                                char const * const alphabet = c->f & F_UPCASE ?
                                    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
                                    "0123456789abcdefghijklmnopqrstuvwxyz";
                                int i = 0;
                                unsigned long save = c->data.u;
                            
                                if (c->f & F_LEFTADJUSTED)
                                    c->f &= ~F_ZEROPADDED;
                            
                                if (c->f & F_ALTERNATE) {
                                    if (c->b == BASE_OCT) {
                                        --c->field;
                                        --c->prec;
                                    }
                                    else if (c->b == BASE_HEXA)
                                        c->field -= 2;
                                }
                            
                                if (c->data.u == 0UL)
                                    buf[i++] = '0';
                            
                                while (c->data.u != 0UL) {
                                    buf[i++] = alphabet[c->data.u % c->b];
                                    c->data.u /= c->b;
                                }
                            
                                if (c->prec == 0 && save == 0UL)
                                    i = 0;
                            
                                c->prec = c->prec < i ? i : c->prec;
                                c->field -= c->prec;
                            
                                if (!(c->f & F_LEFTADJUSTED) && !(c->f & F_ZEROPADDED))
                                    PRINT(c->field-- > 0, ' ', c->dst);
                            
                                if (c->f & F_ALTERNATE) {
                                    if (c->b == BASE_OCT)
                                        PUTC('0', c->dst);
                                    else if (c->b == BASE_HEXA) {
                                        PUTC('0', c->dst);
                                        PUTC(alphabet[33], c->dst);
                                    }
                                }
                            
                                if (c->s != SIGN_NO)
                                    PUTC(c->s, c->dst);
                            
                                if (!(c->f & F_LEFTADJUSTED))
                                    PRINT(c->field-- > 0, c->f & F_ZEROPADDED ? '0' : ' ', c->dst);
                            
                                PRINT(c->prec-- > i, '0', c->dst);
                                PRINT(i-- > 0, buf[i], c->dst);
                                PRINT(c->field-- > 0, ' ', c->dst);
                            
                                return RET_OK;
                            }
                            
                            static int
                            printsigned(conf *c) {
                                if (c->data.n < 0) {
                                    c->s = SIGN_MINUS;
                                    c->data.u = (unsigned long)-c->data.n;
                                } 
                                else if (c->f & F_SHOWSIGN)
                                    c->s = SIGN_PLUS;
                                else if (c->f & F_SPACE)
                                    c->s = SIGN_SPACE;
                            
                                if (c->s != SIGN_NO)
                                    --c->field;
                            
                                return printinteger(c);
                            }
                            
                            static int
                            printnumber(conf *c, va_list **ap) {
                                if (c->q == Q_LARGE) {
                                    if (c->f & F_SIGNED)
                                        c->data.n = va_arg(**ap, long);
                                    else
                                        c->data.u = va_arg(**ap, unsigned long);
                                }
                                else if (c->q == Q_SHORT) {
                                    if (c->f & F_SIGNED)
                                        c->data.n = (short)va_arg(**ap, int);
                                    else
                                        c->data.u = (unsigned short)va_arg(**ap, unsigned);
                                }
                                else if (c->f & F_SIGNED)
                                    c->data.n = va_arg(**ap, int);
                                else
                                    c->data.u = va_arg(**ap, unsigned);
                            
                                return c->f & F_SIGNED ? printsigned(c) : printinteger(c);
                            }
                            
                            static int
                            printstring(conf *c) {
                                int size = 0, i;
                            
                                if (c->data.s == NULL)
                                    c->data.s = "<null>";
                            
                                while (c->data.s[size] != '\0' && (unsigned)size < (unsigned)c->prec)
                                    ++size;
                            
                                if (!(c->f & F_LEFTADJUSTED))
                                    PRINT(c->field-- > size, ' ', c->dst);
                            
                                for (i = 0; i < size; ++i)
                                    PUTC(*c->data.s++, c->dst);
                            
                                PRINT(c->field-- > size, ' ', c->dst);
                            
                                return RET_OK;
                            }
                            
                            static int
                            printwcharstring(conf *c) {
                                int size = 0, i;
                            
                                if (c->data.ls == NULL) {
                                    c->data.ls = L"<null>";
                                    size = 6;
                                }
                            
                                while (c->data.ls[size] != L'\0' && (unsigned)size < (unsigned)c->prec)
                                    ++size;
                            
                                if (!(c->f & F_LEFTADJUSTED))
                                    PRINT(c->field-- > size, ' ', c->dst);
                            
                                for (i = 0; i < size; ++i)
                                    PUTC(*c->data.ls++, c->dst);
                            
                                PRINT(c->field-- > size, ' ', c->dst);
                            
                                return RET_OK;
                            }
                            
                            static int
                            printpointer(conf *c) {
                                unsigned long value = (unsigned long)c->data.p;
                            
                                if (c->field == 0) {
                                    c->field = 2 * sizeof c->data.p;
                                    c->f |= F_ZEROPADDED;
                                }
                            
                                c->f |= F_ALTERNATE;
                            
                                if (value != 0UL) {
                                    c->b = BASE_HEXA;
                                    c->data.u = value;
                                    c->s = SIGN_NO;
                                }
                                else {
                                    c->data.s = "(nil)";
                                    c->prec = 5;
                                }
                            
                                return value == 0UL ? printstring(c) : printinteger(c);
                            }
                            
                            static int
                            initflags(const char ***fmt) {
                                flags f = 0;
                            
                                while (1) {
                                    ++**fmt;
                            
                                    switch (***fmt) {
                                    case '-':
                                        f |= F_LEFTADJUSTED;
                                        break;
                                    case '+':
                                        f |= F_SHOWSIGN;
                                        break;
                                    case ' ':
                                        f |= F_SPACE;
                                        break;
                                    case '#':
                                        f |= F_ALTERNATE;
                                        break;
                                    case '0':
                                        f |= F_ZEROPADDED;
                                        break;
                                    default:
                                        goto end;
                                    }
                                }
                            
                              end:
                                return f;
                            }
                            
                            static int
                            getint(const char ***s) {
                                int i;
                            
                                for (i = 0; isdigit(***s); ++**s)
                                    i = i * 10 + (***s - '0');
                            
                                return i;
                            }
                            
                            static int
                            initfield(const char ***fmt, flags *f, va_list **ap) {
                                int field = 0;
                            
                                if (***fmt == '*') {
                                    ++**fmt;
                                    field = va_arg(**ap, int);
                                } 
                                else if (isdigit(***fmt))
                                    field = getint(fmt);
                            
                                if (field < 0) {
                                    field *= -1;
                                    *f |= F_LEFTADJUSTED;
                                }
                            
                                return field;
                            }
                            
                            static int
                            initprec(const char ***fmt, va_list **ap) {
                                int prec = -1;
                            
                                if (***fmt == '.') {
                                    ++**fmt;
                            
                                    if (***fmt == '*') {
                                        ++**fmt;
                                        prec = va_arg(**ap, int);
                                    } 
                                    else if (isdigit(***fmt))
                                        prec = getint(fmt);
                            
                                    prec = prec < 0 ? 0 : prec;
                                }
                            
                                return prec;
                            }
                            
                            static qualifier
                            initqualifier(const char ***fmt) {
                                qualifier q = Q_NO;
                            
                                switch (***fmt) {
                                case 'h':
                                case 'l':
                                    q = ***fmt;
                                    ++**fmt;
                                }
                            
                                return q;
                            }
                            
                            static int
                            convert(contents *dst, const char **fmt, va_list *ap) {
                                conf c = {dst, {0}, BASE_DEC, 0, 0, 0, SIGN_NO, Q_NO};
                                int ret = RET_OK;
                            
                                if (**fmt != '%') {
                                    PUTC(**fmt, c.dst);
                                    goto end;
                                }
                            
                                c.f = initflags(&fmt);
                                c.field = initfield(&fmt, &c.f, &ap);
                                c.prec = initprec(&fmt, &ap);
                                c.q = initqualifier(&fmt);
                            
                                switch (**fmt) {
                                case 'c':
                                    if (!(c.f & F_LEFTADJUSTED))
                                        PRINT(--c.field > 0, ' ', c.dst);
                            
                                    PUTC(va_arg(*ap, int), c.dst);
                                    PRINT(--c.field > 0, ' ', c.dst);
                                    goto end;
                                case 's':
                                    if (c.q == 'l') {
                                        c.data.ls = va_arg(*ap, wchar_t *);
                                        ret = printwcharstring(&c);
                                    }
                                    else {
                                        c.data.s = va_arg(*ap, char *);
                                        ret = printstring(&c);
                                    }
                            
                                    goto end;
                                case 'p':
                                    c.data.p = va_arg(*ap, void *);
                                    ret = printpointer(&c);
                                    goto end;
                                case 'n':
                                    if (c.q == Q_LARGE) {
                                        long *p = va_arg(*ap, long *);
                                        *p = writed;
                                    } 
                                    else {
                                        int *p = va_arg(*ap, int *);
                                        *p = writed;
                                    }
                                    goto end;
                                case 'o':
                                    c.b = BASE_OCT;
                                    break;
                                case 'X':
                                    c.f |= F_UPCASE;
                                case 'x':
                                    c.b = BASE_HEXA;
                                    break;
                                case 'd': case 'i':
                                    c.f |= F_SIGNED;
                                case 'u':
                                    break;
                                default:
                                    PUTC(**fmt, dst);
                                    goto end;
                                }
                            
                                ret = printnumber(&c, &ap);
                            
                              end:
                                return ret;
                            }
                            
                            int
                            zprintf(const char *format, ...) {
                                va_list ap;
                                int ret;
                            
                                va_start(ap, format);
                                ret = zvfprintf(stdout, format, ap);
                                va_end(ap);
                            
                                return ret;
                            }
                            
                            int
                            zfprintf(FILE *stream, const char *format, ...) {
                                va_list ap;
                                int ret = 0;
                            
                                va_start(ap, format);
                                ret = zvfprintf(stream, format, ap);
                                va_end(ap);
                            
                                return ret;
                            }
                            
                            int
                            zsprintf(char *str, const char *format, ...) {
                                va_list ap;
                                int ret = 0;
                            
                                va_start(ap, format);
                                ret = zvsprintf(str, format, ap);
                                va_end(ap);
                            
                                return ret;
                            }
                            
                            int 
                            zsnprintf(char *str, size_t size, const char *format, ...) {
                                va_list ap;
                                int ret = 0;
                            
                                va_start(ap, format);
                                ret = zvsnprintf(str, size, format, ap);
                                va_end(ap);
                            
                                return ret;
                            }
                            
                            int 
                            zvprintf(const char *format, va_list ap) {
                                return zvfprintf(stdout, format, ap);
                            }
                            
                            int 
                            zvfprintf(FILE *stream, const char *format, va_list ap) {
                                contents dst;
                            
                                writed = 0;
                                dst.type = TYPE_FILE;
                                dst.fs.fp = stream;
                            
                                for (; *format != '\0'; ++format)
                                    if (convert(&dst, &format, &ap) == RET_FAIL)
                                        return -1;
                            
                                return writed;
                            }
                            
                            int
                            zvsprintf(char *str, const char *format, va_list ap) {
                                return zvsnprintf(str, -1UL, format, ap);
                            }
                            
                            int 
                            zvsnprintf(char *str, size_t size, const char *format, va_list ap) {
                                contents dst;
                            
                                writed = 0;
                                dst.type = TYPE_STRING;
                                dst.fs.s.p = str;
                                dst.fs.s.i = 0UL;
                                dst.fs.s.max = size;
                            
                                for (; *format != '\0'; ++format)
                                    if (convert(&dst, &format, &ap) == RET_FAIL)
                                        return -1;
                            
                                str[dst.fs.s.i] = '\0';
                            
                                return writed;
                            }
                            


                            #ifndef H_LP_PRINTF_20120519110725
                            #define H_LP_PRINTF_20120519110725
                            
                            #include <stdio.h>
                            #include <stdarg.h>
                            
                            #ifdef __GNUC__
                                #define FORMAT(x, y) __attribute__ ((format(printf, x, y)))
                            #else
                                #define FORMAT(x, y)
                            #endif
                            
                            int zprintf(const char *format, ...) 
                                FORMAT(1, 2);
                            
                            int zfprintf(FILE *stream, const char *format, ...) 
                                FORMAT(2, 3);
                            
                            int zsprintf(char *str, const char *format, ...) 
                                FORMAT(2, 3);
                            
                            int zsnprintf(char *str, size_t size, const char *format, ...) 
                                FORMAT(3, 4);
                            
                            int zvprintf(const char *format, va_list ap);
                            int zvfprintf(FILE *stream, const char *format, va_list ap);
                            int zvsprintf(char *str, const char *format, va_list ap);
                            int zvsnprintf(char *str, size_t size, const char *format, va_list ap);
                            
                            #endif
                            
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Staff désormais retraité.
                              26 mai 2012 à 18:21:05

                              Taurre > Merde... je vais voir comment je vais faire du coup. ^^
                              Pour le coup de jouer avec les bits, j'ai dit 'recommencer' parce que je retrouve plus le code justement... :(

                              lucas > Pour la précision 0, c'est dit par la norme. Si la précision est 0 et et que le nombre est 0 on n'affiche rien.
                              Pour les tests, ça a l'air de fonctionner là. :)

                              • Partager sur Facebook
                              • Partager sur Twitter
                                26 mai 2012 à 21:10:18

                                Citation : Lucas-84


                                Par ailleurs, tu m'as fait pensé aux wchar_t que j'avais complètement zappé.



                                Attention que ton implémentation n'est pas bonne de ce côté. En effet, il ne faut pas perdre de vue qu'un caractère large doit être converti en un ou plusieurs multicaractères. C'est par exemple le cas si le jeu de caractère de l'environnement d'exécution est l'UTF-8. Il est donc nécessaire de passer par les fonctions de transcodages afin d'obtenir une chaîne de multicaractères et d'afficher cette dernière.

                                Si l'on souhaite rester conforme au C89, cela peut se faire à l'aide de la macroconstante MB_CUR_MAX et de la fonction wcstombs.


                                static int
                                printwcharstring(conf *c) {
                                    int size = 0, i;
                                    char *mbs;
                                    size_t n;
                                
                                    if (c->data.ls == NULL) {
                                        c->data.ls = L"<null>";
                                        size = 6;
                                    }
                                
                                    while (c->data.ls[size] != L'\0' && (unsigned)size < (unsigned)c->prec)
                                        ++size;
                                
                                    if (!(c->f & F_LEFTADJUSTED))
                                        PRINT(c->field-- > size, ' ', c->dst);
                                
                                    mbs = malloc(size * MB_CUR_MAX + 1);
                                
                                    if (mbs == NULL)
                                        return RET_FAIL;
                                
                                    if ((n = wcstombs(mbs, c->data.ls, size * MB_CUR_MAX)) == (size_t)-1)
                                        return RET_FAIL;
                                
                                    mbs[n] = '\0';
                                    for (i = 0; i < n; ++i)
                                        PUTC(mbs[i], c->dst);
                                
                                    PRINT(c->field-- > size, ' ', c->dst);
                                    return RET_OK;
                                }
                                

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Anonyme
                                  27 mai 2012 à 11:02:07

                                  Salut, je participe en niveau 2 pour l'instant, car je ne vois pas comment afficher les nombres à virgule flottante (j'aurai juste à me documenter vite fait sur le net et j'edit ce post).


                                  void numberToStr(int number, char base, char majuscule)
                                  {
                                  	char charset[17] = "0123456789abcdef";
                                  	char buf[10]; //strlen("4294967295") = 10
                                  	int lenght;
                                  	int temp;
                                  
                                  	temp = 0;
                                  	lenght = 0;
                                  
                                  	if(majuscule)
                                  	{
                                  		*(unsigned long*)&charset[10] = 0x44434241; // pour écrire ABCD en litte endian seulement !!
                                  		*(unsigned short*)&charset[14] = 0x4645; // et pour écrire EF en little endian aussi
                                  	}
                                  
                                  
                                  	do
                                  	{
                                  		temp = number % base;
                                  		temp = (temp < 0 ? -temp : temp);
                                  		buf[lenght] = charset[temp];
                                  		number /= base;
                                  		lenght++;
                                  	}
                                  	while(number != 0);
                                  
                                  	while(lenght != 0)
                                  	{
                                  		lenght--;
                                  		fwrite(&buf[lenght], 1, 1, stdout);
                                  	}
                                  
                                  }
                                  /* Je préfère cette fonction car elle affiche vraiment la forme binaire (négative ou pas) */
                                  void printBin(int number)
                                  {
                                  	char displayZero; // permet d'éviter d'afficher les zero inutile
                                  	int i;
                                  
                                  	displayZero = 0;
                                  
                                  	for(i = 31; i >= 0; i--)
                                  	{
                                  		if(number & (1 << i))
                                  		{
                                  			fwrite("1", 1, 1, stdout);
                                  			displayZero = 1;
                                  		}
                                  		else if(displayZero != 0)
                                  		{
                                  			fwrite("0", 1, 1, stdout);
                                  		}
                                  	}
                                  }
                                  
                                  void zPrintf(char* str, ...)
                                  {
                                  	va_list argsList;
                                  	unsigned int i;
                                  	char* tmp;
                                  
                                  	i = 0;	
                                  
                                  	va_start(argsList, str);
                                  		
                                  	while(str[i] != 0)
                                  	{
                                  		if(str[i] == '%')
                                  		{
                                  			switch(str[i+1])
                                  			{
                                  			case 'b':
                                  				{
                                  					printBin(va_arg(argsList, int));
                                  					//numberToStr(va_arg(argsList, int), 2);
                                  					i++;
                                  					break;
                                  				}
                                  			case 'd':
                                  			case 'i':
                                  				{
                                  					numberToStr(va_arg(argsList, int), 10, 0);
                                  					i++;
                                  					break;
                                  				}
                                  			case 'u':
                                  				{
                                  					numberToStr(va_arg(argsList, unsigned int), 10, 0);
                                  					i++;
                                  					break;
                                  				}
                                  			case 'X':
                                  				{
                                  					numberToStr(va_arg(argsList, unsigned int), 16, 1);
                                  					i++;
                                  					break;
                                  				}
                                  			case 'x':
                                  				{
                                  					numberToStr(va_arg(argsList, unsigned int), 16, 0);
                                  					i++;
                                  					break;
                                  				}
                                  			case 'o':
                                  				{
                                  					numberToStr(va_arg(argsList, unsigned int), 8, 0);
                                  					i++;
                                  					break;
                                  				}
                                  			case 's':
                                  				{
                                  					tmp = va_arg(argsList, char*);
                                  					fwrite(tmp, strlen(tmp), 1, stdout);
                                  					i++;
                                  					break;
                                  				}
                                  			case 'c':
                                  				{
                                  					fwrite(&va_arg(argsList, char), 1, 1, stdout);
                                  					i++;
                                  					break;
                                  				}
                                  
                                  			default:
                                  				{
                                  					fwrite(&str[i], 1, 1, stdout);
                                  				}
                                  			}
                                  		}
                                  		else
                                  		{
                                  			fwrite(&str[i], 1, 1, stdout);
                                  		}
                                  		i++;
                                  	}
                                  
                                  	va_end(argsList);	
                                  }
                                  




                                  edit : code entre les balises "secret"
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    27 mai 2012 à 13:37:25

                                    lucas > t'as un souci avec ça : testprintf("%#.0x", 0);

                                    Je crois que je vais laisser mon code tel quel et laisser les flottants de côté. :-°
                                    Ou alors je vais taper sur la division/multiplication, c'est trop reulou comme truc. =D
                                    J'le posterai quand je l'aurai nettoyé. ^^
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      27 mai 2012 à 17:37:22

                                      Voilà mon code. Jusqu’au niveau 2 je crois.

                                      J’ai essayé de respecter au maximum ma page de manuel.
                                      J’ai codé une seule fonction générique (vgnprintf) qui fait tout le boulot principal (avec des fonctions annexes pour écrire un entier, un flottant …), après on n’a plus qu’à coder facilement toutes les autres fonctions (familles sprintf et fprintf) en se basant sur cette dernière. J’ai pas (encore) codé as[n]printf, mais ça peut se faire aussi facilement. On peut même s’en servir pour écrire dans des conteneurs perso.

                                      Je gère :
                                      • les flags ;
                                      • la taille du champ ([édit] y compris avec "*") ;
                                      • la précision ([édit] y compris avec "*") ;
                                      • les modificateurs de type ;
                                      • les conversions suivantes : entiers, pointeurs, caractères et chaînes de caractères (sauf caractères étendus), [édit] et "%n".

                                      Il me reste à implémenter :
                                      • les flottants (comme tout le monde :p ) ;
                                      • les caractères et chaînes de caractères étendus (pas encore les connaissances nécessaires) ;
                                      • la conversion "%n" ;
                                      • les trucs du genre "%*i" ou "%5$i" (la flemme) .


                                      D’autre part, je ne vérifie pas la validité du format (je ne vérifie pas si les paramètres sont dans l’ordre, cohérents, etc.). Je vais corriger ça.

                                      Édit : Nouvelle version du code, avec rajout de fonctionnalités (listes ci-dessus mises à jour). La validité du format est désormais vérifiée (respect de l’ordre des différents champs, rejet des modificateurs de type invalides, début de gestion des erreurs). Également correction d’un bogue avec le flag '0'.

                                      header


                                      /**
                                      ***  printf.h
                                      ***
                                      ***    module:   printf  −  header file
                                      ***    function: imitation of the ‘printf’ functions family. 
                                      ***    author:   Maëlan (aka Maëlan44)
                                      ***              (see < http://www.siteduzero.com/membres-294-232877.html >)
                                      ***
                                      ***    last modified: 2012/05/27, 11h30
                                      ***
                                      **/
                                      
                                      #ifndef INCLUDED_PRINTF_2012_05_25_17_30_MM
                                      #define INCLUDED_PRINTF_2012_05_25_17_30_MM
                                      
                                      #include <stdarg.h>
                                      /* More header! */
                                      #include <stdint.h>       /* uintmax_t, intmax_t, SIZE_MAX */
                                      #include <stddef.h>       /* size_t, ptrdiff_t */
                                      #include <sys/types.h>    /* ssize_t */
                                      #include <wchar.h>        /* wchar_t, wint_t */
                                      #include <ctype.h>        /* isdigit(), toupper() */
                                      #include <string.h>       /* strlen() */
                                      #include <stdio.h>        /* FILE, putc() */
                                      
                                      
                                      
                                      /* The “length modifier” of a conversion (see ‘man 3 printf’). */
                                      typedef enum {
                                          PRINTTYPE_hh,
                                          PRINTTYPE_h,
                                          PRINTTYPE_DEFAULT,
                                          PRINTTYPE_l,
                                          PRINTTYPE_ll,
                                          PRINTTYPE_L,
                                          PRINTTYPE_j,
                                          PRINTTYPE_z,
                                          PRINTTYPE_t
                                      } PrintType;
                                      
                                      /* Options controlling the output of a conversion (see ‘man 3 printf’). */
                                      typedef struct {
                                          size_t  width;      /* (minimum) field width (0: no width specified) */
                                          size_t  precis;     /* precision */
                                          PrintType  type;    /* … */
                                          _Bool  alt    :1,    /* '#' flag (use alternate form) */
                                                 zpad   :1,    /* '0' flag (pad with zero digits) */
                                                 alignl :1,    /* '-' flag (align to the left) */
                                                 space  :1,    /* ' ' flag (print a space for positive numbers)  */
                                                 plus   :1,    /* '+' flag (print a plus sign for positive numbers) */
                                                 /* additional boolean informations for internal use */
                                                 cap    :1,    /* Write uppercase letters (for hexa)? */
                                                 neg    :1,    /* Is the number negative? */
                                                 hasPrecis  :1;    /* Has a precision been specified? */
                                      } PrintOpt;
                                      #define  PRINTOPT_DEFAULTINIT  \
                                          { .type = PRINTTYPE_DEFAULT }    /* all others members to zero */
                                      
                                      /* Generic ‘printf’ context: the buffer to write into (with any real type),
                                       * informations about it, and the current conversion options. */
                                      typedef struct {
                                          void*  p;    /* generic buffer to print into (can be ‘char*’, ‘FILE*’…) */
                                          size_t i,    /* number of characters already written */
                                                 n;    /* maximal number of characters to write */
                                          PrintOpt opt;    /* … */
                                      } PrintFrame;
                                      
                                      
                                      
                                      /* Type of pointer to a function capable of writing one character in the buffer;
                                       * depending on the behaviour wanted, such a function must or must not write the
                                       * character if i >= n, but in all cases it must increment i. Those functions
                                       * are used to achieve genericity, they are called by all the generic functions
                                       * to write a character. */
                                      typedef  void (*PrintcF)(PrintFrame*, wint_t);
                                      
                                      
                                      
                                      /* The core (most generic) ‘printf’ function. */
                                      int vgnprintf(PrintcF, void* buf, size_t n, const char* fmt, va_list);
                                      
                                      /* All the standard ‘printf’ functions. */
                                      
                                      int vsnprintf(char* dest, size_t, const char* fmt, va_list);
                                      int vsprintf(char* dest, const char* fmt, va_list);
                                      int vfprintf(FILE* dest, const char* fmt, va_list);
                                      int vprintf(const char* fmt, va_list);
                                      
                                      int snprintf(char* dest, size_t, const char* fmt, ...);
                                      int sprintf(char* dest, const char* fmt, ...);
                                      int fprintf(FILE* dest, const char* fmt, ...);
                                      int printf(const char* fmt, ...);
                                      
                                      
                                      
                                      #endif
                                      


                                      source (ancienne version)

                                      </span>
                                      /**
                                      ***  printf.c
                                      ***
                                      ***    module:   printf  −  source file
                                      ***    function: imitation of the ‘printf’ functions family. 
                                      ***    author:   Maëlan (aka Maëlan44)
                                      ***              (see < http://www.siteduzero.com/membres-294-232877.html >)
                                      ***
                                      ***    last modified: 2012/05/27, 12h30
                                      ***
                                      **/
                                      
                                      #include "printf.h"
                                      
                                      
                                      
                                      /** Functions fetching an argument passed via ‘...’, depending on the type
                                       ** passed, which is specified by the length modifier …
                                       **/
                                      
                                      /* … for an unsigned integer; */
                                      static  uintmax_t vgetUint(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_hh:         return (unsigned char)  va_arg(*ap, int);
                                            case PRINTTYPE_h:          return (unsigned short) va_arg(*ap, int);
                                            /*case PRINTTYPE_hh:         return va_arg(ap, unsigned char);
                                            case PRINTTYPE_h:          return va_arg(ap, unsigned short);*/
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, unsigned int);
                                            case PRINTTYPE_l:          return va_arg(*ap, unsigned long);
                                            case PRINTTYPE_ll:         return va_arg(*ap, unsigned long long);
                                            case PRINTTYPE_j:          return va_arg(*ap, uintmax_t);
                                            case PRINTTYPE_z:          return va_arg(*ap, size_t);
                                            case PRINTTYPE_t:          return va_arg(*ap, ptrdiff_t);
                                            default:     return 0;
                                          }
                                      }
                                      
                                      /* … for a signed integer; */
                                      static  intmax_t vgetInt(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_hh:         return (signed char)  va_arg(*ap, int);
                                            case PRINTTYPE_h:          return (signed short) va_arg(*ap, int);
                                            /*case PRINTTYPE_hh:         return va_arg(ap, signed char);
                                            case PRINTTYPE_h:          return va_arg(ap, signed short);*/
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, signed int);
                                            case PRINTTYPE_l:          return va_arg(*ap, signed long);
                                            case PRINTTYPE_ll:         return va_arg(*ap, signed long long);
                                            case PRINTTYPE_j:          return va_arg(*ap, intmax_t);
                                            case PRINTTYPE_z:          return va_arg(*ap, ssize_t);
                                            case PRINTTYPE_t:          return va_arg(*ap, ptrdiff_t);
                                            default:     return 0;
                                          }
                                      }
                                      
                                      /* … for a floating number; */
                                      static  long double vgetFloat(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, double);
                                            case PRINTTYPE_L:          return va_arg(*ap, long double);
                                            default:     return 0.0;
                                          }
                                      }
                                      
                                      /* … for a character; */
                                      static  wint_t vgetChar(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, int);
                                            case PRINTTYPE_l:          return va_arg(*ap, wint_t);
                                            default:     return 0;
                                          }
                                      }
                                      
                                      /* … for a character string (basically an array of the appropriate character
                                       * type). */
                                      static  const void* vgetString(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, const char*);
                                            case PRINTTYPE_l:          return va_arg(*ap, const wchar_t*);
                                            default:     return NULL;
                                          }
                                      }
                                      /*#define  vgetString(ap, type)   va_arg((ap), char*)
                                      #define  vgetWString(ap, type)  va_arg((ap), wchar_t*)*/
                                      
                                      
                                      
                                      /* Read an (unsigned) decimal integer in the character string pointed to, and
                                       * return its value. Increment the character pointer so it points on the first
                                       * non-digit character. */
                                      static  unsigned int readUint(const char** sp) {
                                          unsigned int  r;
                                          for(r = 0;  isdigit(**sp);  ++*sp)
                                              r = r*10 + **sp-'0';
                                          return r;
                                      }
                                      
                                      
                                      
                                      /** Functions writing the data on the buffer with the conversion options …
                                       **/
                                      
                                      /* … for an unsigned integer; */
                                      static  void gnprintUint(PrintcF printc, PrintFrame* buf, uintmax_t n, unsigned int base) {
                                          static const char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
                                          char tmp[256];
                                          size_t i, j;
                                          
                                          /* default precision for integers (write just the required digits) */
                                          if(!buf->opt.hasPrecis)
                                              buf->opt.precis = 1;
                                          
                                          /* The '0' flag is ignored if the  '-' flag or a precision is present. */
                                          if(buf->opt.zpad && !buf->opt.alignl && !buf->opt.hasPrecis)
                                              /* To pad with '0', we use the mechanism of precision, which controls
                                                 the minimal number of digits to write (width-1 because of the sign
                                                 character). */
                                              buf->opt.precis = (buf->opt.width)? buf->opt.width-1 : 0;
                                          else
                                              buf->opt.zpad = 0;
                                          
                                          /* digits */
                                          for(i = 0;  n  ||  i < buf->opt.precis;  ++i) {
                                              tmp[i] = digits[n % base];
                                              if(buf->opt.cap)
                                                  tmp[i] = toupper(tmp[i]);
                                              n /= base;
                                          }
                                          
                                          /* prefix */
                                          if(buf->opt.alt) {
                                              if(base==16)
                                                  tmp[i++] = (buf->opt.cap)? 'X' : 'x';
                                              if(base==16 || base==8)
                                                  tmp[i++] = '0';
                                          }
                                          
                                          /* sign */
                                          if(buf->opt.neg)
                                              tmp[i++] = '-';
                                          else if(buf->opt.plus)
                                              tmp[i++] = '+';
                                          else if(buf->opt.space)
                                              tmp[i++] = ' ';
                                          else if(buf->opt.zpad)    /* if we pad with '0' and no sign character is */
                                              tmp[i++] = '0';       /* written, we add a '0' to fulfil the width.  */
                                          
                                          /* left padding */
                                          if(!buf->opt.alignl)
                                              while(buf->opt.width-- > i)
                                                  printc(buf, ' ');
                                          
                                          /* writing the number itself, with its eventual sign */
                                          j = i;    /* save the length, because we need it later for right padding */
                                          while(i--)
                                              printc(buf, tmp[i]);
                                          
                                          /* right padding */
                                          if(buf->opt.alignl)
                                              while(buf->opt.width-- > j)
                                                  printc(buf, ' ');
                                      }
                                      
                                      /* … for a signed integer: */
                                      static  void gnprintInt(PrintcF printc, PrintFrame* buf, intmax_t n, unsigned int base) {
                                          if(n<0) {
                                              buf->opt.neg = 1;
                                              n = -n;
                                          }
                                          gnprintUint(printc, buf, n, base);
                                      }
                                      
                                      /* (Output style for a floating number.) */
                                      typedef enum {
                                          PRINTSTYLE_SCI,        /* corresponds to "%e" */
                                          PRINTSTYLE_NATURAL,    /* corresponds to "%f" */
                                          PRINTSTYLE_MIX,        /* corresponds to "%g" */
                                          PRINTSTYLE_HEX         /* corresponds to "%a" */
                                      } PrintFloatStyle;
                                      
                                      /* … for a floating number; */
                                      static  void gnprintFloat(PrintcF printc, PrintFrame* buf, long double f, PrintFloatStyle style) {
                                          /* … */
                                          ;
                                      }
                                      
                                      /* … for a wide character string; */
                                      static  void gnprintWString(PrintcF printc, PrintFrame* buf, const wchar_t* s) {
                                          /* … */
                                          ;
                                      }
                                      
                                      /* … for a character string in general (including a wide character string). */
                                      static  void gnprintString(PrintcF printc, PrintFrame* buf, const char* s) {
                                          if(buf->opt.type == PRINTTYPE_l)
                                              gnprintWString(printc, buf, (const wchar_t*)s);
                                          
                                          if(!s)
                                              s = "(null)";
                                          
                                          size_t i;
                                              
                                          /* default precision for strings (write all the characters) */
                                          if(!buf->opt.hasPrecis)
                                              buf->opt.precis = SIZE_MAX;
                                          
                                          /* left padding */
                                          if(buf->opt.width && !buf->opt.alignl) {
                                              size_t len = strlen(s);
                                              if(buf->opt.hasPrecis  &&  buf->opt.precis < len)
                                                  len = buf->opt.precis;
                                              while(buf->opt.width-- > len)
                                                  printc(buf, ' ');
                                          }
                                          
                                          /* the string itself */
                                          for(i = 0;  s[i]  &&  i < buf->opt.precis;  ++i)
                                              printc(buf, s[i]);
                                          
                                          /* right padding */
                                          if(buf->opt.width && buf->opt.alignl)
                                              while(buf->opt.width-- > i)
                                                  printc(buf, ' ');
                                      }
                                      
                                      
                                      
                                      /** The core (most generic) ‘printf’ function.
                                       **/
                                      
                                      int vgnprintf(PrintcF printc, void* p, size_t n, const char* fmt, va_list ap) {
                                          if(!p || !n || !fmt)
                                              return 0;
                                          
                                          PrintFrame  buf =  { p, 0, n, PRINTOPT_DEFAULTINIT };
                                          
                                          for(;  *fmt;  ++fmt) {
                                              /* Output a normal character. */
                                              if(*fmt != '%')
                                                  printc(&buf, *fmt);
                                              
                                              /* Output a formated conversion. */
                                              else {
                                                  buf.opt = (PrintOpt) PRINTOPT_DEFAULTINIT;
                                                  
                                                  /* Format analysis */
                                                again:
                                                  switch(*++fmt) {
                                                    
                                                    /* Output flags */
                                                    
                                                    case '#':
                                                      buf.opt.alt = 1;
                                                      goto again;
                                                    case '0':
                                                      buf.opt.zpad = 1;
                                                      goto again;
                                                    case '-':
                                                      buf.opt.alignl = 1;
                                                      goto again;
                                                    case ' ':
                                                      buf.opt.space = 1;
                                                      goto again;
                                                    case '+':
                                                      buf.opt.plus = 1;
                                                      goto again;
                                                    
                                                    
                                                    /* Field width */
                                                    
                                                    //case '0':
                                                    case '1':
                                                    case '2':
                                                    case '3':
                                                    case '4':
                                                    case '5':    /* case powaa! */
                                                    case '6':
                                                    case '7':
                                                    case '8':
                                                    case '9':
                                                      buf.opt.width = readUint(&fmt);
                                                      --fmt;
                                                      goto again;
                                                    
                                                    
                                                    /* Precision */
                                                    
                                                    case '.':
                                                      ++fmt;
                                                      buf.opt.precis = readUint(&fmt);
                                                      --fmt;
                                                      buf.opt.hasPrecis = 1;
                                                      goto again;
                                                    
                                                    
                                                    /* Argument type (“length modifier”) */
                                                    
                                                    case 'h':
                                                      --buf.opt.type;    /* /!\ unsecure (assuming correct format) */
                                                      goto again;
                                                    case 'l':
                                                      ++buf.opt.type;    /* /!\ unsecure (assuming correct format) */
                                                      goto again;
                                                    case 'L':
                                                      buf.opt.type = PRINTTYPE_L;
                                                      goto again;
                                                    case 'j':
                                                      buf.opt.type = PRINTTYPE_j;
                                                      goto again;
                                                    case 'z':
                                                      buf.opt.type = PRINTTYPE_z;
                                                      goto again;
                                                    case 't':
                                                      buf.opt.type = PRINTTYPE_t;
                                                      goto again;
                                                    
                                                    
                                                    /* Conversions */
                                                    
                                                    case 'd':
                                                    case 'i':
                                                      gnprintInt(printc, &buf, vgetInt(&ap, buf.opt.type), 10);
                                                      break;
                                                    
                                                    case 'u':
                                                      gnprintUint(printc, &buf, vgetUint(&ap, buf.opt.type), 10);
                                                      break;
                                                    
                                                    case 'o':
                                                      gnprintUint(printc, &buf, vgetUint(&ap, buf.opt.type), 010);
                                                      break;
                                                    
                                                    case 'X':
                                                      buf.opt.cap = 1;
                                                    case 'x':
                                                      gnprintUint(printc, &buf, vgetUint(&ap, buf.opt.type), 0x10);
                                                      break;
                                                    
                                                    case 'E':
                                                      buf.opt.cap = 1;
                                                    case 'e':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_SCI);
                                                      break;
                                                    
                                                    case 'F':
                                                      buf.opt.cap = 1;
                                                    case 'f':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_NATURAL);
                                                      break;
                                                    
                                                    case 'G':
                                                      buf.opt.cap = 1;
                                                    case 'g':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_MIX);
                                                      break;
                                                    
                                                    case 'A':
                                                      buf.opt.cap = 1;
                                                    case 'a':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_HEX);
                                                      break;
                                                    
                                                    case 'c':
                                                      printc(&buf, vgetChar(&ap, buf.opt.type));
                                                      break;
                                                    
                                                    case 's':
                                                      gnprintString(printc, &buf, vgetString(&ap, buf.opt.type));
                                                      break;
                                                    
                                                    case 'p':
                                                      buf.opt.alt = 1;
                                                      gnprintUint(printc, &buf, (uintmax_t)(uintptr_t)va_arg(ap, void*), 16);
                                                      break;
                                                    
                                                    case '%':
                                                      printc(&buf, '%');
                                                      break;
                                                    
                                                    default:
                                                      break;
                                                  }
                                              }
                                          }
                                          
                                          return buf.i;
                                      }
                                      
                                      
                                      
                                      /** Functions writing a character on the buffer of a specific type. See the
                                       ** comments about the ‘F_gnprintc’ type in <printf.h> for more details.
                                       **/
                                      
                                      /* Function for use with ‘snprintf’: write a character on a character string, if
                                       * the size does not exceed the maximal size.
                                       * We should code an unsecure version of this function for use with ‘sprintf’
                                       * (called ‘sprintChar’, and not verifying the size before writing), but since
                                       * a ‘size_t’ integer is big enough to index any byte in the memory, this
                                       * function with the size ‘SIZE_MAX’ will fit. */
                                      static  void snprintChar(PrintFrame* buf, wint_t c) {
                                          if(buf->i < buf->n)
                                              ((char*)buf->p)[buf->i] = (char)c;
                                          ++buf->i;
                                      }
                                      
                                      /* Function for use with ‘fprintf’: write a charadter on a file. We do not need
                                       * a secure version since ‘fnprintf’ does not exist, and moreover calling a
                                       * secure version with the size ‘SIZE_MAX’ could not fit, because we might want
                                       * to write more than ‘SIZE_MAX’ bytes into the disk (). */
                                      static  void fprintChar(PrintFrame* buf, wint_t c) {
                                          putc(c, buf->p);
                                          ++buf->i;
                                      }
                                      
                                      
                                      
                                      /** At least, all the standard ‘printf’ functions. 
                                       **/
                                      
                                      int vsnprintf(char* dest, size_t n, const char* fmt, va_list ap) {
                                          int r = vgnprintf(snprintChar, dest, n, fmt, ap);
                                          if((size_t)r < n)
                                              dest[r] = '\0';
                                          return r;
                                      }
                                      
                                      int vsprintf(char* dest, const char* fmt, va_list ap) {
                                          return vsnprintf(dest, SIZE_MAX, fmt, ap);
                                      }
                                      
                                      int snprintf(char* dest, size_t n, const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vsnprintf(dest, n, fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      
                                      int sprintf(char* dest, const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vsprintf(dest, fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      
                                      int vfprintf(FILE* f, const char* fmt, va_list ap) {
                                          return vgnprintf(fprintChar, f, SIZE_MAX, fmt, ap);
                                      }
                                      
                                      int vprintf(const char* fmt, va_list ap) {
                                          return vfprintf(stdout, fmt, ap);
                                      }
                                      
                                      int fprintf(FILE* f, const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vfprintf(f, fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      
                                      int printf(const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vprintf(fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      


                                      Source (version à jour)


                                      /**
                                      ***  printf.c
                                      ***
                                      ***    module:   printf  −  source file
                                      ***    function: imitation of the ‘printf’ functions family. 
                                      ***    author:   Maëlan (aka Maëlan44)
                                      ***              (see < http://www.siteduzero.com/membres-294-232877.html >)
                                      ***
                                      ***    last modified: 2012/05/27, 12h30
                                      ***
                                      **/
                                      
                                      #include "printf.h"
                                      
                                      
                                      
                                      /** Functions fetching an argument passed via ‘...’, depending on the type
                                       ** passed, which is specified by the length modifier …
                                       **/
                                      
                                      /* … for an unsigned integer; */
                                      static  uintmax_t vgetUint(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_hh:         return (unsigned char)  va_arg(*ap, int);
                                            case PRINTTYPE_h:          return (unsigned short) va_arg(*ap, int);
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, unsigned int);
                                            case PRINTTYPE_l:          return va_arg(*ap, unsigned long);
                                            case PRINTTYPE_L:    /* non standard (L modifier for integers) */
                                            case PRINTTYPE_ll:         return va_arg(*ap, unsigned long long);
                                            case PRINTTYPE_j:          return va_arg(*ap, uintmax_t);
                                            case PRINTTYPE_z:          return va_arg(*ap, size_t);
                                            case PRINTTYPE_t:          return va_arg(*ap, ptrdiff_t);
                                            //default:     return 0;
                                          }
                                      }
                                      
                                      /* … for a signed integer; */
                                      static  intmax_t vgetInt(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_hh:         return (signed char)  va_arg(*ap, int);
                                            case PRINTTYPE_h:          return (signed short) va_arg(*ap, int);
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, signed int);
                                            case PRINTTYPE_l:          return va_arg(*ap, signed long);
                                            case PRINTTYPE_L:    /* non standard (L modifier for integers) */
                                            case PRINTTYPE_ll:         return va_arg(*ap, signed long long);
                                            case PRINTTYPE_j:          return va_arg(*ap, intmax_t);
                                            case PRINTTYPE_z:          return va_arg(*ap, ssize_t);
                                            case PRINTTYPE_t:          return va_arg(*ap, ptrdiff_t);
                                            //default:     return 0;
                                          }
                                      }
                                      
                                      /* … for a floating number; */
                                      static  long double vgetFloat(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, double);
                                            case PRINTTYPE_L:          return va_arg(*ap, long double);
                                            default:     return 0.0;
                                          }
                                      }
                                      
                                      /* … for a character; */
                                      static  wint_t vgetChar(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, int);
                                            case PRINTTYPE_l:          return va_arg(*ap, wint_t);
                                            default:     return 0;
                                          }
                                      }
                                      
                                      /* … for a character string (basically an array of the appropriate character
                                       * type). */
                                      static  const void* vgetString(va_list* ap, PrintType type) {
                                          switch(type) {
                                            case PRINTTYPE_DEFAULT:    return va_arg(*ap, const char*);
                                            case PRINTTYPE_l:          return va_arg(*ap, const wchar_t*);
                                            default:     return NULL;
                                          }
                                      }
                                      
                                      
                                      
                                      /* Read an (unsigned) decimal integer in the character string pointed to, and
                                       * return its value. Increment the character pointer so it points on the first
                                       * non-digit character. */
                                      static  unsigned int readUint(const char** sp, va_list* ap) {
                                          if(**sp == '*') {
                                              ++*sp;
                                              return va_arg(*ap, int);
                                          }
                                      
                                          unsigned int  r;
                                          for(r = 0;  isdigit(**sp);  ++*sp)
                                              r = r*10 + **sp-'0';
                                          return r;
                                      }
                                      
                                      
                                      
                                      /** Functions writing the data on the buffer with the conversion options …
                                       **/
                                      
                                      /* … for an unsigned integer; */
                                      static  void gnprintUint(PrintcF printc, PrintFrame* buf, uintmax_t n, unsigned int base) {
                                          static const char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
                                          char tmp[256];
                                          size_t i, j;
                                          
                                          /* default precision for integers (write just the required digits) */
                                          if(!buf->opt.hasPrecis)
                                              buf->opt.precis = 1;
                                          
                                          /* The '0' flag is ignored if the  '-' flag or a precision is present. */
                                          if(buf->opt.zpad && !buf->opt.alignl && !buf->opt.hasPrecis)
                                              /* To pad with '0', we use the mechanism of precision, which controls
                                                 the minimal number of digits to write (width-1 because of the sign
                                                 character). */
                                              buf->opt.precis = (buf->opt.width)? buf->opt.width-1 : 0;
                                          else
                                              buf->opt.zpad = 0;
                                          
                                          /* digits */
                                          for(i = 0;  n  ||  i < buf->opt.precis;  ++i) {
                                              tmp[i] = digits[n % base];
                                              if(buf->opt.cap)
                                                  tmp[i] = toupper(tmp[i]);
                                              n /= base;
                                          }
                                          
                                          /* prefix */
                                          if(buf->opt.alt) {
                                              if(base==16)
                                                  tmp[i++] = (buf->opt.cap)? 'X' : 'x';
                                              if(base==16 || base==8)
                                                  tmp[i++] = '0';
                                          }
                                          
                                          /* sign */
                                          if(buf->opt.neg)
                                              tmp[i++] = '-';
                                          else if(buf->opt.plus)
                                              tmp[i++] = '+';
                                          else if(buf->opt.space)
                                              tmp[i++] = ' ';
                                          else if(buf->opt.zpad && i<buf->opt.width)
                                              tmp[i++] = '0';      /* if we pad with '0' and no sign character is */ 
                                                                   /* written, we add a '0' to fulfil the width.  */
                                          
                                          /* left padding */
                                          if(!buf->opt.alignl)
                                              while(buf->opt.width-- > i)
                                                  printc(buf, ' ');
                                          
                                          /* writing the number itself, with its eventual sign */
                                          j = i;    /* save the length, because we need it later for right padding */
                                          while(i--)
                                              printc(buf, tmp[i]);
                                          
                                          /* right padding */
                                          if(buf->opt.alignl)
                                              while(buf->opt.width-- > j)
                                                  printc(buf, ' ');
                                      }
                                      
                                      /* … for a signed integer: */
                                      static  void gnprintInt(PrintcF printc, PrintFrame* buf, intmax_t n, unsigned int base) {
                                          if(n<0) {
                                              buf->opt.neg = 1;
                                              n = -n;
                                          }
                                          gnprintUint(printc, buf, n, base);
                                      }
                                      
                                      /* (Output style for a floating number.) */
                                      typedef enum {
                                          PRINTSTYLE_SCI,        /* corresponds to "%e" */
                                          PRINTSTYLE_NATURAL,    /* corresponds to "%f" */
                                          PRINTSTYLE_MIX,        /* corresponds to "%g" */
                                          PRINTSTYLE_HEX         /* corresponds to "%a" */
                                      } PrintFloatStyle;
                                      
                                      /* … for a floating number; */
                                      static  void gnprintFloat(PrintcF printc, PrintFrame* buf, long double f, PrintFloatStyle style) {
                                          /* … */
                                          ;
                                      }
                                      
                                      /* … for a wide character string; */
                                      static  void gnprintWString(PrintcF printc, PrintFrame* buf, const wchar_t* s) {
                                          /* … */
                                          ;
                                      }
                                      
                                      /* … for a character string in general (including a wide character string). */
                                      static  void gnprintString(PrintcF printc, PrintFrame* buf, const char* s) {
                                          if(buf->opt.type == PRINTTYPE_l)
                                              gnprintWString(printc, buf, (const wchar_t*)s);
                                          
                                          static const char null[] = "(null)";
                                          size_t i;
                                          
                                          if(!s)
                                              s = null;
                                          
                                          /* default precision for strings (write all the characters) */
                                          if(!buf->opt.hasPrecis)
                                              buf->opt.precis = SIZE_MAX;
                                          
                                          /* left padding */
                                          if(buf->opt.width && !buf->opt.alignl) {
                                              size_t len = strlen(s);
                                              if(buf->opt.hasPrecis  &&  buf->opt.precis < len)
                                                  len = buf->opt.precis;
                                              while(buf->opt.width-- > len)
                                                  printc(buf, ' ');
                                          }
                                          
                                          /* the string itself */
                                          for(i = 0;  s[i]  &&  i < buf->opt.precis;  ++i)
                                              printc(buf, s[i]);
                                          
                                          /* right padding */
                                          if(buf->opt.width && buf->opt.alignl)
                                              while(buf->opt.width-- > i)
                                                  printc(buf, ' ');
                                      }
                                      
                                      
                                      
                                      /** The core (most generic) ‘printf’ function.
                                       **/
                                      
                                      int vgnprintf(PrintcF printc, void* p, size_t n, const char* fmt, va_list ap) {
                                          if(!p || !n || !fmt)
                                              return 0;
                                          
                                          PrintFrame  buf =  { p, 0, n, PRINTOPT_DEFAULTINIT };
                                          
                                          for(;  *fmt;  ++fmt) {
                                              /* Output a normal character. */
                                              if(*fmt != '%')
                                                  printc(&buf, *fmt);
                                              
                                              /* Output a formated conversion (format analysis). */
                                              else {
                                                  const char* fmtBegin = fmt;   /* (see below, when invalid format) */
                                                  buf.opt = (PrintOpt) PRINTOPT_DEFAULTINIT;
                                                    
                                                  /* Output flags */
                                                    
                                                flagsAgain:
                                                  switch(*++fmt) {
                                                    case '#':
                                                      buf.opt.alt = 1;
                                                      goto flagsAgain;
                                                    case '0':
                                                      buf.opt.zpad = 1;
                                                      goto flagsAgain;
                                                    case '-':
                                                      buf.opt.alignl = 1;
                                                      goto flagsAgain;
                                                    case ' ':
                                                      buf.opt.space = 1;
                                                      goto flagsAgain;
                                                    case '+':
                                                      buf.opt.plus = 1;
                                                      goto flagsAgain;
                                                    default:
                                                      break;
                                                  }
                                                   
                                                  
                                                   /* Field width */
                                                  
                                                  buf.opt.width = readUint(&fmt, &ap);
                                                  
                                                  
                                                  /* Precision */
                                                  
                                                  if(*fmt == '.') {
                                                      ++fmt;
                                                      buf.opt.precis = readUint(&fmt, &ap);
                                                      buf.opt.hasPrecis = 1;
                                                  }
                                                  
                                                  
                                                  /* Argument type (“length modifier”) */
                                                    
                                                  switch(*fmt++) {
                                                    case 'h':
                                                      /*if(*fmt == 'h') {
                                                          buf.opt.type = PRINTTYPE_hh;
                                                          ++fmt;
                                                      }
                                                      else
                                                          buf.opt.type = PRINTTYPE_h;*/
                                                      buf.opt.type = (*fmt == 'h' && ++fmt)? PRINTTYPE_hh : PRINTTYPE_h;
                                                      break;
                                                    case 'l':
                                                      /*if(*fmt == 'l') {
                                                          buf.opt.type = PRINTTYPE_ll;
                                                          ++fmt;
                                                      }
                                                      else
                                                          buf.opt.type = PRINTTYPE_l;*/
                                                      buf.opt.type = (*fmt == 'l' && ++fmt)? PRINTTYPE_ll : PRINTTYPE_l;
                                                      break;
                                                    case 'L':
                                                      buf.opt.type = PRINTTYPE_L;
                                                      break;
                                                    case 'j':
                                                      buf.opt.type = PRINTTYPE_j;
                                                      break;
                                                    case 'z':
                                                      buf.opt.type = PRINTTYPE_z;
                                                      break;
                                                    case 't':
                                                      buf.opt.type = PRINTTYPE_t;
                                                      break;
                                                    default:
                                                      --fmt;
                                                      break;
                                                  }
                                                  
                                                  
                                                  /* Conversions */
                                                  
                                                  switch(*fmt) {
                                                    case 'd':
                                                    case 'i':
                                                      gnprintInt(printc, &buf, vgetInt(&ap, buf.opt.type), 10);
                                                      break;
                                                    
                                                    case 'u':
                                                      gnprintUint(printc, &buf, vgetUint(&ap, buf.opt.type), 10);
                                                      break;
                                                    
                                                    case 'o':
                                                      gnprintUint(printc, &buf, vgetUint(&ap, buf.opt.type), 010);
                                                      break;
                                                    
                                                    case 'X':
                                                      buf.opt.cap = 1;
                                                    case 'x':
                                                      gnprintUint(printc, &buf, vgetUint(&ap, buf.opt.type), 0x10);
                                                      break;
                                                    
                                                    case 'E':
                                                      buf.opt.cap = 1;
                                                    case 'e':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_SCI);
                                                      break;
                                                    
                                                    case 'F':
                                                      buf.opt.cap = 1;
                                                    case 'f':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_NATURAL);
                                                      break;
                                                    
                                                    case 'G':
                                                      buf.opt.cap = 1;
                                                    case 'g':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_MIX);
                                                      break;
                                                    
                                                    case 'A':
                                                      buf.opt.cap = 1;
                                                    case 'a':
                                                      gnprintFloat(printc, &buf, vgetFloat(&ap, buf.opt.type), PRINTSTYLE_HEX);
                                                      break;
                                                    
                                                    case 'c':
                                                      printc(&buf, vgetChar(&ap, buf.opt.type));
                                                      break;
                                                    
                                                    case 's':
                                                      gnprintString(printc, &buf, vgetString(&ap, buf.opt.type));
                                                      break;
                                                    
                                                    case 'p':
                                                      buf.opt.alt = 1;
                                                      gnprintUint(printc, &buf, (uintmax_t)(uintptr_t)va_arg(ap, void*), 16);
                                                      break;
                                                    
                                                    case 'n':
                                                      switch(buf.opt.type) {
                                                        case PRINTTYPE_hh:         
                                                          * va_arg(ap, char*)      = buf.i;    break;
                                                        case PRINTTYPE_h:
                                                          * va_arg(ap, short*)     = buf.i;    break;
                                                        case PRINTTYPE_DEFAULT:
                                                          * va_arg(ap, int*)       = buf.i;    break;
                                                        case PRINTTYPE_l:
                                                          * va_arg(ap, long*)      = buf.i;    break;
                                                        case PRINTTYPE_L:    /* non standard (L for integers) */
                                                        case PRINTTYPE_ll:
                                                          * va_arg(ap, long long*) = buf.i;    break;
                                                        case PRINTTYPE_j:
                                                          * va_arg(ap, intmax_t*)  = buf.i;    break;
                                                        case PRINTTYPE_z:
                                                          * va_arg(ap, ssize_t*)   = buf.i;    break;
                                                        case PRINTTYPE_t:
                                                          * va_arg(ap, ptrdiff_t*) = buf.i;    break;
                                                        //default:     return -1;
                                                      }
                                                      break;
                                                    
                                                    /*case '%':
                                                      printc(&buf, '%');
                                                      break;*/
                                                    
                                                    default:    /* invalid format: print the format itself */
                                                      //printc(&buf, '%');
                                                      fmt = fmtBegin;
                                                    case '%':
                                                      printc(&buf, '%');
                                                      break;
                                                      //return -1;    /* error: invalid format */
                                                  }
                                              }
                                          }
                                          
                                          return buf.i;
                                      }
                                      
                                      
                                      
                                      /** Functions writing a character on the buffer of a specific type. See the
                                       ** comments about the ‘F_gnprintc’ type in <printf.h> for more details.
                                       **/
                                      
                                      /* Function for use with ‘snprintf’: write a character on a character string, if
                                       * the size does not exceed the maximal size.
                                       * We should code an unsecure version of this function for use with ‘sprintf’
                                       * (called ‘sprintChar’, and not verifying the size before writing), but since
                                       * a ‘size_t’ integer is big enough to index any byte in the memory, this
                                       * function with the size ‘SIZE_MAX’ will fit. */
                                      static  void snprintChar(PrintFrame* buf, wint_t c) {
                                          if(buf->i < buf->n)
                                              ((char*)buf->p)[buf->i] = (char)c;
                                          ++buf->i;
                                      }
                                      
                                      /* Function for use with ‘fprintf’: write a character on a file. We do not need
                                       * a secure version since ‘fnprintf’ does not exist, and moreover calling a
                                       * secure version with the size ‘SIZE_MAX’ could not fit, because we might want
                                       * to write more than ‘SIZE_MAX’ bytes into the disk (). */
                                      static  void fprintChar(PrintFrame* buf, wint_t c) {
                                          putc(c, buf->p);
                                          ++buf->i;
                                      }
                                      
                                      
                                      
                                      /** At least, all the standard ‘printf’ functions. 
                                       **/
                                      
                                      int vsnprintf(char* dest, size_t n, const char* fmt, va_list ap) {
                                          int r = vgnprintf(snprintChar, dest, n, fmt, ap);
                                          if((size_t)r < n)
                                              dest[r] = '\0';
                                          return r;
                                      }
                                      
                                      int vsprintf(char* dest, const char* fmt, va_list ap) {
                                          return vsnprintf(dest, SIZE_MAX, fmt, ap);
                                      }
                                      
                                      int snprintf(char* dest, size_t n, const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vsnprintf(dest, n, fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      
                                      int sprintf(char* dest, const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vsprintf(dest, fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      
                                      int vfprintf(FILE* f, const char* fmt, va_list ap) {
                                          return vgnprintf(fprintChar, f, SIZE_MAX, fmt, ap);
                                      }
                                      
                                      int vprintf(const char* fmt, va_list ap) {
                                          return vfprintf(stdout, fmt, ap);
                                      }
                                      
                                      int fprintf(FILE* f, const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vfprintf(f, fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      
                                      int printf(const char* fmt, ...) {
                                          va_list ap;
                                          int r;
                                          va_start(ap, fmt);
                                          r = vprintf(fmt, ap);
                                          va_end(ap);
                                          return r;
                                      }
                                      


                                      pour tester


                                      Pour comparer avec le comportement standard, il suffit de ne pas lier avec printf.c.
                                      #include "printf.h"
                                      
                                      #define test(fmt, ...)  \
                                          do {  \
                                              r = snprintf(buf, 36, fmt, ##__VA_ARGS__);  \
                                              printf("#%-2i [%02i] %10s   “%s”%n", i++, r, fmt, buf, &n);  \
                                              printf("\t\t(→ %2i)\n", n);  \
                                          } while(0)
                                      
                                      int main(void) {
                                          char buf[1024];
                                          int  i = 0, r, n = 666;
                                          
                                          long                li = 1;
                                          long long          lli = 2;
                                          unsigned long long llu = 3;
                                          ptrdiff_t           ti = 4;
                                          ssize_t             zi = 5;
                                          size_t              zu = 6;
                                          short               hi = 7;
                                          unsigned char      hhu = 8;
                                          intmax_t            ji = 9;
                                          uintmax_t           ju = 10;
                                          
                                          /* ptr */
                                          fprintf(stdout, "  buf: %p\n", buf);
                                          fprintf(stdout, "  n: %p\n", &n);
                                          
                                          /* % */
                                          test("%%");
                                          
                                          /* simple integer conversions, some flags (sign, alt) */
                                          test("%d",   42);
                                          test("%i",   -42);
                                          test("% i",  42);
                                          test("%+i",  42);
                                          test("%+ i", 42);
                                          test("%+ i", -42);
                                          test("%X",   42);
                                          test("%#x",  42);
                                          test("%#o",  42);
                                          
                                          /* precision, width, padding (spaces or '0' flag), alignment ('-' flag) */
                                          test("%.5d",    42);
                                          test("%0+.5d",  42);
                                          test("%0+9.5d", 42);
                                          test("%9.5d",   42);
                                          test("%-+9.5d", 42);
                                          test("%.i",     42);
                                          test("%.i",     0);
                                          test("%+.i",    0);
                                          test("%17.i",   0);
                                          
                                          /* more */
                                          test("%5d",   42);
                                          test("%5d",   -42);
                                          test("%05d",  42);
                                          test("%05d",  -42);
                                          test("%+05d", 42);
                                          test("% 5d",  42);
                                          test("% 5d",  -42);
                                          test("%-5d",  42);
                                          test("%- 5d", 42);
                                          test("%-5d",  -42);
                                          test("%-05d", -42);
                                          test("%-30d", -42);
                                          
                                          /* pad (spaces or zeros) when too large */
                                          test("%6d",   314159);
                                          test("%5d",   314159);
                                          test("%5d",   -314159);
                                          test("%08d",  314159);
                                          test("%07d",  314159);
                                          test("%06d",  314159);
                                          test("%05d",  314159);
                                          
                                          /* strings (width, precision, padding, null) */
                                          test("%s",      "123456789,123456789,123456789,123456789.");   /* error: not enough space for ‘snprintf’ (limited to 36 in the ‘test’ macro) */
                                          test("%20s",    "123456789.");
                                          test("%.5s",    "123456789.");
                                          test("%20.5s",  "123456789.");
                                          test("%-20s",   "123456789.");
                                          test("%-20.5s", "123456789.");
                                          test("%-20.15s", "123456789.");
                                          test("%-5.15s", "123456789.");
                                          test("%20.15s", "123456789.");
                                          test("%5.15s", "123456789.");
                                          test("%s",      (char*)NULL);
                                          test("%20s",    (char*)NULL);
                                          test("%.5s",    (char*)NULL);
                                          test("%20.5s",  (char*)NULL);
                                          test("%s",      "");
                                          test("% s",     "");
                                          
                                          /* types */
                                          test("%li",   li);
                                          test("%lli",   lli);
                                          test("%llu",  llu);
                                          test("%ti",  ti);
                                          test("%zi",  ti);
                                          test("%zi",  zi);
                                          test("%zu", zu);
                                          test("%hi", hi);
                                          test("%hhu",   hhu);
                                          test("%ji",  ji);
                                          test("%ju",  ju);
                                          test("%ju",  hhu);    /* error: bad type */
                                          
                                          /* '*' for width or precision */
                                          test("%*u",  10, 123);
                                          test("%.*u",  10, 123);
                                          test("%*.*u",  10, 5, 123);
                                          
                                          /* “n” conversions */
                                          test("%i%n",  123, &n);
                                          test("%i%Ln",  123, &n);
                                          
                                          /* invalid format */
                                          test("%lhu", 123);
                                          test("%hlu", 123);
                                          test("%h u", 123);
                                          test("%h5u", 123);
                                          test("%h.5u", 123);
                                          test("%.5.6u", 123);
                                      
                                          return 0;
                                      }
                                      


                                      Voilà voilà.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        27 mai 2012 à 21:48:58

                                        Voilà mon code. J'suis pas trop satisfait, je fais beaucoup de if...else pour pas grand chose je pense. Je verrai pour améliorer ça si je suis motivé. :)
                                        Tout est géré (ou partiellement) sauf %n, et tous les flottants. Le partiellement, c'est pour tout ce qui touche aux size_t, ptrdiff_t et conneries du genre. J'ai pris un type arbitraire. :-°

                                        #include <ctype.h>
                                        #include <float.h>
                                        #include <inttypes.h>
                                        #include <limits.h>
                                        #include <math.h>
                                        #include <stdarg.h>
                                        #include <stddef.h>
                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        #include <string.h>
                                        #include <wchar.h>
                                        
                                        #define aprintf(...) fprintf(stderr, __VA_ARGS__)
                                        
                                        enum {
                                          FLG_MINUS = 0x01,
                                          FLG_PLUS  = 0x02,
                                          FLG_SPACE = 0x04,
                                          FLG_SHARP = 0x08,
                                          FLG_ZERO  = 0x10
                                        };
                                        
                                        enum {
                                          LEN_hh,
                                          LEN_ll,
                                          LEN_h,
                                          LEN_l,
                                          LEN_j,
                                          LEN_z,
                                          LEN_t,
                                          LEN_L,
                                          N_LEN
                                        };
                                        
                                        
                                        typedef enum {
                                          TYP_C,    /* char */
                                          TYP_S,    /* short */
                                          TYP_I,    /* int */
                                          TYP_L,    /* long */
                                          TYP_LL,   /* long long */
                                          TYP_F,    /* float */
                                          TYP_D,    /* double */
                                          TYP_LD,   /* long double */
                                          TYP_IMAX, /* uintmax_t */
                                        
                                          TYP_SZT,  /* size_t */
                                          TYP_PDIF, /* ptrdiff_t */
                                          
                                          TYP_WC,    /* wchar_t */
                                          TYP_PVOID  /* void* */
                                          
                                        } type_e;
                                        
                                        /* Type sign */
                                        enum {
                                          SIG_U = 0x01,
                                          SIG_S = 0x02,
                                          SIG_x = 0x04,
                                          SIG_X = 0x08
                                        };
                                        
                                        enum {
                                          ENDIAN_BIG,
                                          ENDIAN_LIT
                                        };
                                        
                                        typedef union {
                                          unsigned char uc;
                                          unsigned long long ull;
                                          unsigned short us;
                                          unsigned long ul;
                                          unsigned int ui;
                                          uintmax_t uimax;
                                          size_t szt;
                                          ptrdiff_t pdif;
                                          
                                          wchar_t wc;
                                          
                                          void * pvoid;
                                          
                                          long double ld;
                                          double d;
                                          float f;
                                        } types_u;
                                        
                                        typedef struct args_s {
                                          unsigned flags;
                                          int fieldWidth;
                                          int precision;
                                          int lenMod;
                                        } args_t;
                                        
                                        void initArgs(args_t * ag) {
                                          ag->flags = 0;
                                          ag->fieldWidth = -1;
                                          ag->precision = -1;
                                          ag->lenMod = -1;
                                        }
                                        
                                        /* Search flags after a % character */
                                        const char * getFlags(const char * fmt, args_t * ag) {
                                          char flags[] = "-+ #0";
                                          int dflags[] = {
                                            FLG_MINUS, FLG_PLUS, FLG_SPACE, FLG_SHARP, FLG_ZERO 
                                          };
                                          const char * t;
                                          
                                          while (1) {
                                            t = strchr(flags, *fmt);
                                            if (t) {
                                              ag->flags |= dflags[t - flags];
                                              fmt++;
                                            }
                                            else {
                                              break;
                                            }
                                          }
                                          
                                          /* If + and space are presents, space is ignored */
                                          if (ag->flags & FLG_PLUS && ag->flags & FLG_SPACE) {
                                            aprintf("'+' and ' ' flag are presents. ' ' is ignored.\n");
                                            ag->flags ^= FLG_SPACE;
                                          }
                                          /* If - and 0 are present, 0 is ignored */
                                          if (ag->flags & FLG_MINUS && ag->flags & FLG_ZERO) {
                                            aprintf("'+' and '0' flag are presents. '0' is ignored.\n");
                                            ag->flags ^= FLG_ZERO;
                                          }
                                          
                                          return fmt;
                                        }
                                        
                                        const char * getPrecision(const char * fmt, int * precision, va_list * ap) {
                                          
                                          if (*fmt == '*') {
                                            *precision = va_arg(*ap, int);
                                            fmt++;
                                          }
                                          else if (isdigit(*fmt)) {
                                            int n = 0;
                                            
                                            do {
                                              n *= 10;
                                              n += (*fmt - '0');
                                              fmt++;
                                            } while (isdigit(*fmt));
                                            
                                            *precision = n;
                                          }
                                          
                                          return fmt;
                                        }
                                        
                                        const char * getLenMod(const char * fmt, args_t * ag) {
                                          /* Note: the multichar characters are placed before single bye char */
                                          char * mods[N_LEN] = {
                                            "hh", "ll", "h", "l", "j", "z", "t", "L"
                                          };
                                          int lenMods[N_LEN] = {
                                            2, 2, 1, 1, 1, 1, 1, 1
                                          };
                                          int dmods[N_LEN] = {
                                            LEN_hh, LEN_ll, LEN_h, LEN_l, LEN_j, LEN_z, LEN_t, LEN_L
                                          };
                                          int i;
                                          
                                          for (i = 0; i < N_LEN; i++) {
                                            if (strncmp(mods[i], fmt, lenMods[i]) == 0) {
                                              ag->lenMod = dmods[i];
                                              fmt += lenMods[i];
                                              break;
                                            }
                                          }
                                          
                                          return fmt;
                                        }
                                        
                                        
                                        int printIntJustify(FILE * f, char * s, int offset, args_t * ag) {
                                          int sz = strlen(s);
                                          int precision;
                                          int fieldw;
                                          int np;
                                          int i;
                                          
                                          if (sz - offset < ag->precision)
                                            precision = ag->precision - sz + offset;
                                          else
                                            precision = 0;
                                          
                                          if (sz + precision < ag->fieldWidth)
                                            fieldw = ag->fieldWidth - (sz + precision);
                                          else
                                            fieldw = 0;
                                          
                                          np = 0;
                                          
                                          if (ag->flags & FLG_ZERO) {
                                            if (ag->precision < 0 || sz + precision < ag->precision) {
                                              for (i = 0; i < fieldw; i++) {
                                                fputc('0', f);
                                                np++;
                                              }
                                            }
                                            else {
                                              for (i = 0; i < fieldw; i++) {
                                                fputc(' ', f);
                                                np++;
                                              }
                                            }
                                          }
                                          else if ((ag->flags & FLG_MINUS) == 0) {
                                            for (i = 0; i < fieldw; i++) {
                                              fputc(' ', f);
                                              np++;
                                            }
                                          }
                                          
                                          for (i = 0; i < offset; i++) {
                                            fputc(s[i], f);
                                            np++;
                                          }
                                          
                                          for (i = 0; i < precision; i++) {
                                            fputc('0', f);
                                            np++;
                                          }
                                          
                                          for (i = offset; s[i]; i++) {
                                            fputc(s[i], f);
                                            np++;
                                          }
                                          
                                          if (ag->flags & FLG_MINUS) {
                                            for (i = 0; i < fieldw; i++) {
                                              fputc(' ', f);
                                              np++;
                                            }
                                          }
                                          
                                          return np;
                                        }
                                        
                                        int printStrJustify(FILE * f, char * s, wchar_t * sw, int nchar, args_t * ag) {
                                          int sz;
                                          int np;
                                          int i;
                                          
                                          if (s)
                                            sz = strlen(s);
                                          else
                                            sz = wcslen(sw);
                                          
                                          if (nchar >= 0)
                                            sz = nchar;
                                          
                                          np = 0;
                                          
                                          if ((ag->flags & FLG_MINUS) == 0) {
                                            for (i = 0; i < ag->fieldWidth - sz; i++) {
                                              if (s)
                                                fputc(' ', f);
                                              else
                                                fputwc(L' ', f);
                                              np++;
                                            }
                                          }
                                          
                                          for (i = 0; ((s && s[i]) || (sw && sw[i])) && i < sz; i++) {
                                            if (s)
                                              fputc(s[i], f);
                                            else
                                              fputwc(sw[i], f);
                                            np++;
                                          }
                                          
                                          if (ag->flags & FLG_MINUS) {
                                            
                                            for (i = np; i < ag->fieldWidth; i++) {
                                              if (s)
                                                fputc(' ', f);
                                              else
                                                fputwc(L' ', f);
                                              np++;
                                            }
                                          }
                                            
                                          return np;
                                        }
                                        
                                        int getEndian(void) {
                                          unsigned n = 0x12;
                                          char * p = (char *) &n;
                                          
                                          if (*p == 0x12)
                                            return ENDIAN_LIT;
                                          else
                                            return ENDIAN_BIG;
                                        }
                                        
                                        char * getDigit(char * s, unsigned long long ull, int base, char * ascii) {
                                          if (ull >= (unsigned long long) base)
                                            s = getDigit(s, ull / base, base, ascii);
                                          
                                          *s = ascii[ull % base];
                                          return s + 1;
                                        }
                                        
                                        int printInteger(FILE * f, types_u n, int sign, type_e type, int base, args_t * ag) {
                                          char snb[32] = "";
                                          char * s = snb;
                                          unsigned long long ull;
                                          static char * ascii = "0123456789abcdefghijklmnopqrstuvwxyz";
                                          static char * asciiX = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                                          int offset;
                                          
                                          ull = 0;
                                          
                                          if (sign == SIG_S) {
                                            if (type == TYP_I && (int) n.ui < 0) {
                                              ull = - (int) n.ui;
                                              *s++ = '-';
                                            }
                                            else if (type == TYP_C && (char) n.uc < 0) {
                                              ull = - (char) n.uc;
                                              *s++ = '-';
                                            }
                                            else if (type == TYP_S && (short) n.us < 0) {
                                              ull = - (short) n.us;
                                              *s++ = '-';
                                            }
                                            else if (type == TYP_L && (long) n.ul < 0) {
                                              ull = - (long) n.ul;
                                              *s++ = '-';
                                            }
                                            else if (type == TYP_LL && (long long) n.ull < 0) {
                                              ull = - (long long) n.ull;
                                              *s++ = '-';
                                            }
                                            else if (type == TYP_IMAX && (intmax_t) n.uimax < 0) {
                                              ull = - (intmax_t) n.uimax;
                                              *s++ = '-';
                                            }
                                            else if (ag->flags & FLG_PLUS) {
                                              *s++ = '+';
                                            }
                                            else if (ag->flags & FLG_SPACE) {
                                              *s++ = ' ';
                                            }
                                          }
                                          
                                          if (ull == 0) {
                                            if (type == TYP_I) {
                                              ull = n.ui;
                                            }
                                            else if (type == TYP_C) {
                                              ull = n.uc;
                                            }
                                            else if (type == TYP_S) {
                                              ull = n.us;
                                            }
                                            else if (type == TYP_L) {
                                              ull = n.ul;
                                            }
                                            else if (type == TYP_LL) {
                                              ull = n.ull;
                                            }
                                            else if (type == TYP_SZT) {
                                              ull = n.szt;
                                            }
                                            else if (type == TYP_PVOID) {
                                              int endian = getEndian();
                                              
                                              /* TODO: check this out ! fixme... */
                                              if (endian == ENDIAN_BIG) {
                                                ull = (unsigned long long) n.pvoid;
                                              }
                                              else {
                                                ull = (unsigned long long) n.pvoid;
                                              }
                                            }
                                            /* Special case... */
                                            else if (type == TYP_PDIF) {
                                              if (ag->flags & FLG_PLUS)
                                                *s++ = '+';
                                              else if (ag->flags & FLG_SPACE)
                                                *s++ = ' ';
                                              ull = n.pdif;
                                            }
                                          }
                                          
                                          if ((ull != 0 && (ag->flags & FLG_SHARP)) || type == TYP_PVOID) {
                                            *s++ = '0';
                                            
                                            if (base == 16) {
                                              if (sign & SIG_x)
                                                *s++ = 'x';
                                              else
                                                *s++ = 'X';
                                            }
                                          }
                                          
                                          if (ag->precision == 0 && ull == 0 && (ag->flags & FLG_SHARP) == 0) {
                                            return 0;
                                          }
                                          
                                          offset = s - snb;
                                          if (sign & SIG_x)
                                            getDigit(s, ull, base, ascii);
                                          else
                                            getDigit(s, ull, base, asciiX);
                                          
                                          return printIntJustify(f, snb, offset, ag);
                                        }
                                        
                                        int treatInteger(FILE * f, const char ** fmt, args_t * ag, va_list * ap) {
                                          const char * s = *fmt;
                                          types_u nb;
                                          type_e type;
                                          int sign;
                                          int base;
                                          int n;
                                          
                                          if (*s == 'd' || *s == 'i') {
                                            sign = SIG_S;
                                            base = 10;
                                          }
                                          else if (*s == 'u') {
                                            sign = SIG_U;
                                            base = 10;
                                          }
                                          else if (*s == 'o') {
                                            sign = SIG_U;
                                            base = 8;
                                          }
                                          else if (*s == 'x' || *s == 'X' || *s == 'p') {
                                            sign = SIG_U;
                                            if (*s == 'x' || *s == 'p')
                                              sign |= SIG_x;
                                            else
                                              sign |= SIG_X;
                                            
                                            base = 16;
                                          }
                                          else {
                                            aprintf("Wrong formater 'treatInteger'.\n");
                                            return 0;
                                          }
                                          
                                          if (*s == 'p') {
                                            nb.pvoid = va_arg(*ap, void *);
                                            type = TYP_PVOID;
                                          }
                                          else if (ag->lenMod < 0) {
                                            nb.ui = va_arg(*ap, unsigned int);
                                            type = TYP_I;
                                          }
                                          else if (ag->lenMod == LEN_hh) {
                                            nb.uc = (unsigned char) va_arg(*ap, unsigned int);
                                            type = TYP_C;
                                          }
                                          else if (ag->lenMod == LEN_ll) {
                                            nb.ull = va_arg(*ap, unsigned long long);
                                            type = TYP_LL;
                                          }
                                          else if (ag->lenMod == LEN_h) {
                                            nb.us = (unsigned short) va_arg(*ap, unsigned int);
                                            type = TYP_S;
                                          }
                                          else if (ag->lenMod == LEN_l) {
                                            nb.ul = va_arg(*ap, unsigned long);
                                            type = TYP_L;
                                          }
                                          else if (ag->lenMod == LEN_j) {
                                            nb.uimax = va_arg(*ap, uintmax_t);
                                            type = TYP_IMAX;
                                          }
                                          else if (ag->lenMod == LEN_z) {
                                            nb.szt = va_arg(*ap, size_t);
                                            type = TYP_SZT;
                                          }
                                          else if (ag->lenMod == LEN_t) {
                                            nb.pdif = va_arg(*ap, ptrdiff_t);
                                            sign = SIG_U;
                                            type = TYP_PDIF;
                                          }
                                          else {
                                            aprintf("Wrong formater %c.\n", **fmt);
                                            return 0;
                                          }
                                          
                                          n = printInteger(f, nb,sign, type, base, ag);
                                          
                                          *fmt = s + 1;
                                          return n;
                                        }
                                        
                                        
                                        
                                        /* Return the number of char written */
                                        int treatArg(FILE * f, const char ** fmt, args_t * ag, va_list * ap) {
                                          const char * s = *fmt;
                                          int n = 0;
                                          
                                          switch (*s) {
                                            case 'o': case 'u': case 'x': case 'X':
                                              if (ag->flags & FLG_PLUS) {
                                                aprintf("'+' flags with '%c' formater. '+' ignored.\n", *s);
                                                ag->flags ^= FLG_PLUS;
                                              }
                                              
                                              if (ag->flags & FLG_SPACE) {
                                                aprintf("' ' flags with '%c' formater. ' ' ignored.\n", *s);
                                                ag->flags ^= FLG_SPACE;
                                              }
                                              
                                              n = treatInteger(f, &s, ag, ap);
                                              
                                              break;
                                            case 'd': case 'i':
                                              if (ag->flags & FLG_SHARP) {
                                                aprintf("'#' flags with '%c' formater. '+' ignored.\n", *s);
                                                ag->flags ^= FLG_SHARP;
                                              }
                                              
                                              n = treatInteger(f, &s, ag, ap);
                                              
                                              break;
                                            
                                            case 'c':
                                              s++;
                                              
                                              if (ag->flags & (FLG_PLUS | FLG_SHARP | FLG_SPACE | FLG_ZERO)) {
                                                aprintf("Only '-' flag is accepted with 'c' formater.\n");
                                                return 0;
                                              }
                                              if (ag->precision >= 0) {
                                                aprintf("Precision used with 'c' formater.\n");
                                                return 0;
                                              }
                                              
                                              if (ag->lenMod == LEN_L) {
                                                wchar_t wstmp[2] = L"";
                                                
                                                wstmp[0] = (wchar_t) va_arg(*ap, unsigned int);
                                                n = printStrJustify(f, NULL, wstmp, -1, ag);
                                              }
                                              else {
                                                char stmp[2] = "";
                                                
                                                stmp[0] = (unsigned char) va_arg(*ap, unsigned int);
                                                n = printStrJustify(f, stmp, NULL, -1, ag);
                                              }
                                              
                                              break;
                                              
                                            case 's': {
                                              char * stmp;
                                              wchar_t * wstmp;
                                              int nchar;
                                              
                                              s++;
                                              
                                              if (ag->flags & (FLG_PLUS | FLG_SHARP | FLG_SPACE | FLG_ZERO)) {
                                                aprintf("Only '-' flag is accepted with 'c' formater.\n");
                                                return 0;
                                              }
                                              
                                              if (ag->lenMod == LEN_l) {
                                                wstmp = va_arg(*ap, wchar_t *);
                                                stmp = NULL;
                                              }
                                              else {
                                                stmp = va_arg(*ap, char *);
                                                wstmp = NULL;
                                              }
                                              
                                              nchar = -1;
                                              if (ag->precision >= 0) {
                                                int sz;
                                                
                                                if (stmp)
                                                  sz = strlen(stmp);
                                                else
                                                  sz = wcslen(wstmp);
                                                
                                                if (sz > ag->precision) {
                                                  nchar = ag->precision;
                                                }
                                              }
                                              
                                              n = printStrJustify(f, stmp, wstmp, nchar, ag);
                                              break;
                                            }
                                            
                                            case 'p':
                                              if (ag->flags & (FLG_PLUS | FLG_SHARP | FLG_SPACE | FLG_ZERO)) {
                                                aprintf("Only '-' flag is accepted with 'p' formater.\n");
                                                return 0;
                                              }
                                              if (ag->precision >= 0) {
                                                aprintf("Precision used with 'p' formater.\n");
                                                return 0;
                                              }
                                              
                                              n = treatInteger(f, &s, ag, ap);
                                              
                                              break;
                                              
                                            default:
                                              break;
                                          }
                                          
                                          *fmt = s;
                                          return n;
                                        }
                                        
                                        int printArg(FILE * f, const char ** fmt, va_list * ap) {
                                          const char * s = *fmt;
                                          args_t ag;
                                          int n;
                                          
                                          if (**fmt == '%') {
                                            if (fputc('%', f) != EOF)
                                              return 1;
                                            else
                                              return 0;
                                          }
                                          
                                          initArgs(&ag);
                                          
                                          s = getFlags(s, &ag);
                                          s = getPrecision(s, &ag.fieldWidth, ap);
                                          if (*s == '.') {
                                            s++;
                                            s = getPrecision(s, &ag.precision, ap);
                                          }
                                          s = getLenMod(s, &ag);
                                          
                                          n = treatArg(f, &s, &ag, ap);
                                          
                                          *fmt = s;
                                          return n;
                                        }
                                        
                                        
                                        int zvfprintf(FILE * f, const char * fmt, va_list ap) {
                                          int n;
                                          
                                          for (n = 0; *fmt != '\0'; ) {
                                            switch (*fmt) {
                                              case '%':
                                                fmt++;
                                                n += printArg(f, &fmt, &ap);
                                                break;
                                              default:
                                                fputc(*fmt, f);
                                                fmt++;
                                                n++;
                                                break;
                                            }
                                          }
                                          
                                          return n;
                                        }
                                        
                                        int zvprintf(const char * fmt, va_list ap) {
                                          return zvfprintf(stdout, fmt, ap);
                                        }
                                        
                                        int zfprintf(FILE * f, const char * fmt, ...) {
                                          va_list ap;
                                        	int n;
                                          
                                        	va_start(ap, fmt);
                                          n = zvfprintf(f, fmt, ap);
                                        	va_end(ap);
                                        	
                                          return n;
                                        }
                                        
                                        int zprintf(const char * fmt, ...) {
                                        	va_list ap;
                                        	int n;
                                          
                                        	va_start(ap, fmt);
                                          n = zvfprintf(stdout, fmt, ap);
                                        	va_end(ap);
                                        	
                                          return n;
                                        }
                                        
                                        #define mprintf(...) {  printf(": [%d]\n", printf(__VA_ARGS__));     \
                                                                printf(": [%d]\n", zprintf(__VA_ARGS__)); }
                                        
                                        int main(void) {
                                          unsigned int n = 0x1000;
                                          
                                          mprintf("%20p", &n);
                                          mprintf("%#.0x [%c] [%-3.1s]", 0, 'e', "salut");
                                          
                                          mprintf ("Characters: %c %c ", 'a', 65);
                                          mprintf ("Decimals: %d %ld", 1977, 650000L);
                                          mprintf ("Preceding with blanks: %10d ", 1977);
                                          mprintf ("Preceding with zeros: %010d ", 1977);
                                          mprintf ("Some different radixes: %d %x %o %#x %#o ", 100, 100, 100, 100, 100);
                                          mprintf ("floats: %4.2f %+.0e %E ", 3.1416, 3.1416, 3.1416);
                                          mprintf ("Width trick: %*d ", 5, 10);
                                          mprintf ("%s ", "A string");
                                          
                                          static wchar_t wstr[] = L"abcdefghijk";
                                          
                                          mprintf("|1234567890123|");
                                          mprintf("|%13ls|", wstr);
                                          mprintf("|%-13.9ls|", wstr);
                                          mprintf("|%13.10ls|", wstr);
                                          mprintf("|%13.11ls|", wstr);
                                          mprintf("|%13.15ls|", &wstr[2]);
                                          mprintf("|%13lc|", (wint_t) wstr[5]);
                                          
                                          fflush(stdout);
                                          return EXIT_SUCCESS;
                                        }
                                        

                                        Dans certains cas, j'ai mit des messages d'erreurs, mais je l'ai pas fait partout, ça alourdit énormément le code. :-°
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          17 juin 2012 à 22:54:17

                                          Je peux me permettre ?
                                          C'est histoire que j'avais vu le défis quand il a été poster et je voulais vraiment le faire, mais j'ai pas eu assez de temps (exam et truck du genre...)
                                          Et aussi le titre n'est pas préfixer avec [FAIT]. :-°

                                          En plus c'est une participation basique pour le niveau 2 uniquement. :euh:

                                          #include <stdio.h>
                                          #include <stdlib.h>
                                          #include <stdarg.h>
                                          
                                          static int size(char *str)
                                          {
                                              int i;
                                              for(i = 0; str[i] != '\0'; i++);
                                              return i;
                                          }
                                          static char* convert(int n, int base)
                                          {
                                              const char *alpha = "0123456789ABCDEF";
                                              char *s = NULL;
                                              char  *_s = NULL;
                                              int digit = 0, i = 0,j,k = 0, tmp = n;
                                          
                                              while(tmp > 0)
                                              {
                                                  digit++;
                                                  tmp /= base;
                                              }
                                          
                                              s = malloc(digit * sizeof(char));
                                              _s = malloc(digit * sizeof(char));
                                          
                                              if(!s || !_s)  exit(EXIT_FAILURE);
                                          
                                              while(n > 0)
                                              {
                                                  s[i] = alpha[n % base];
                                                  n /= base;
                                                  i++;
                                              }
                                              for(j = i-1; j>=0; j--, k++)
                                                  _s[k] = s[j];
                                          
                                              free(s), s = NULL;
                                              return _s;
                                          }
                                          static void __putchar(char  c)
                                          {
                                              fwrite(&c, sizeof(char),1,stdout);
                                          }
                                          static int eval(char *str, va_list ap)
                                          {
                                              int i,x,ret = 0, siz, base = 10;
                                              char *s = NULL;
                                              for(i = 0; str[i] != '\0'; i++)
                                              {
                                                  if(str[i] == '%')
                                                  {
                                                      i++;
                                                      switch(str[i])
                                                      {
                                                      case '%':
                                                          __putchar('%');
                                                          ret++;
                                                          break;
                                                      case 'd':
                                                      case 'i':
                                                          base = 10;
                                                          x = va_arg(ap, int);
                                                          if(x < 0)
                                                          {
                                                              x = -x;
                                                              __putchar('-');
                                                              ret++;
                                                          }
                                                          s = convert(x, base);
                                                          siz = size(s);
                                                          for(; *s != '\0'; s++)
                                                          {
                                                              __putchar(*s);
                                                              ret++;
                                                          }
                                                          s -= siz;
                                                          free(s), s = NULL;
                                                          break;
                                                      case 'x':
                                                          base = 18;
                                                      case 'o':
                                                          base -= 2;
                                                          x = va_arg(ap, int);
                                                          if(x < 0)
                                                          {
                                                              x = -x;
                                                              __putchar('-');
                                                              ret++;
                                                          }
                                                          s = convert(x, base);
                                                          siz = size(s);
                                                          for(; *s != '\0'; s++)
                                                          {
                                                              __putchar(*s);
                                                              ret++;
                                                          }
                                                          s -= siz;
                                                          free(s), s = NULL;
                                                          break;
                                                      case 'c':
                                                          __putchar(va_arg(ap, int));
                                                          ret++;
                                                          break;
                                                      case 's':
                                                          s  = va_arg(ap, char*);
                                                          for(; *s != '\0'; s++)
                                                          {
                                                              __putchar(*s);
                                                              ret++;
                                                          }
                                          
                                                          break;
                                                      }
                                                  }
                                                  else
                                                  {
                                                      __putchar(str[i]);
                                                      ret++;
                                                  }
                                              }
                                              return ret;
                                          }
                                          static int zprintf(char *str, ...)
                                          {
                                              int ret;
                                              va_list ap;
                                              va_start(ap, str);
                                              ret = eval(str,ap);
                                              va_end(ap);
                                              return ret;
                                          }
                                          int main(void)
                                          {
                                              zprintf("Print : %%  %o  %x  %d %c %s \n",0xA,0xA,0xA, 'c', "Salut");
                                              return 0;
                                          }
                                          


                                          EDIT : Indentation.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            18 juin 2012 à 9:15:10

                                            Chaud l'indentation de 1 espace... 2 à la rigueur, mais là c'est pas très lisible. ;)
                                            J'ai pas regardé en détail ni testé mais le malloc ça le fait mal dans un printf.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Staff désormais retraité.
                                              18 juin 2012 à 18:29:22

                                              Désolé pour l'indentation je l'ai fait à la main. J'ai édité.

                                              Pourquoi le malloc est mal dans un printf ? ( une éventuelle super grosse chaîne qui peut le faire bogué ?)
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                18 juin 2012 à 18:36:44

                                                Bah printf est une fonction qu'on utilise souvent, si elle commence à faire des allocations mémoires, ça peut devenir problématique (d'ailleurs, tu ne pourrais pas supprimer une des deux allocations ? Il me semblait avoir vu des codes n'utilisant qu'un seul tableau. Mais bon, à confirmer)... AMHA tu devrais le faire en statique et fixer une taille plafond. Mais bon, c'est pas essentiel non plus. Par ailleurs, on dirait que tu as réutilisé ma vieille fonction __putchar. Fais gaffe, elle est boguée (cf. remarque de Taurre première page).
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Staff désormais retraité.
                                                  18 juin 2012 à 20:25:29

                                                  Du coup pour éviter le malloc, on doit passer par des fonctions secondaires qui font l'affichage, ou bien tout simplement le faire en statique. Pour les deux allocations je pense que c'est possible d'en laisser qu'une seule,mais tu sais la flemme.

                                                  Et pour la fonction __putchar, j'ai pas vu la remarque de Taurre ( ni ta fonction d'ailleur :-°), j'essayerai de faire une autre.

                                                  Merci pour le feedback. ;)
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Anonyme
                                                    18 juin 2012 à 20:29:43

                                                    Citation : Taurre


                                                    static inline size_t
                                                    __putchar(int c) {
                                                        return fwrite(&c, 1, 1, stdout);
                                                    }
                                                    



                                                    Attention qu'avec cette fonction tu écris le byte de poids faible de la variable c, tu écriras donc probablement 0 sur une machine big endian. De plus, le retour de putchar doit être de type int (retourne EOF en cas d'erreur) et non size_t.

                                                    EDIT : Aussi, les noms d'identificateurs commençant par deux underscores sont réservés et ne doivent par conséquent pas être utilisés ;)

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      18 juin 2012 à 20:33:09

                                                      @informaticienzéro : Je voulais dire je l'avais pas vu, avant de poster le code.
                                                      Mais merci de l'avoir citer ;)
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Anonyme
                                                        18 juin 2012 à 20:50:24

                                                        Ah ok. Bah de rien alors. :)
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Anonyme
                                                          21 mai 2013 à 15:24:32

                                                          Salut à tous,

                                                          Après un long temps et beaucoup d'efforts, voici une nouvelle version de mon code. Je mets le lien GitHub pour ne pas gêner la lecture du topic car le code est long. Merci d'avance à tous les courageux qui reliront.

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter

                                                          [Défis]#11 : zPrintf

                                                          × 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