Forum: Mikrocontroller und Digitale Elektronik smartes printf


von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hi Leutz,

wen's interessiert, ich hab ein minimales printf geschrieben.

Aufruf und Parameterliste wie printf, im Moment werden aber nur:

%i (6 Stellen, kann jeder selber erweitern)
%c
%s

sowie

\n
\t

unterstützt.

Mein Projekt ist damit um ca. 5k kleiner geworden, mein printf braucht 
(keil-compiler) <300k

Bleibt nur noch der retarget auf welches IO auch immer. Ich habe fürs 
retargeting an der fputc angesetzt, diese schreibt auf den UART. Für 
dieses printf hab ich die einfach weiterverwendet, man kann aber auch 
was eigenes statt der fputc einbauen, was z.B. auf den uart schreibt.



Viel Spass damit!

Anregungen und konstruktive Kritik erwünscht ;-)
Anmerkung: Dies ist die erste Version g


---------------
Header:

#ifndef _THPRINTF_H_
#define _THPRINTF_H_


int thprintf(char *string, ...);

#endif



C-File:



// Th printf

/*
Author: Thorsten de Buhr
mail: thorsten@lasertechnix.de

Use:
Use is free, could run or not ;-)

U may change every printf in cour code to thprintf, the rest is the 
same.

U may use:
%i, %s, %c
\n, \t

More is not implemented now.

Have fun with this very small print-function, it uses ~300 bytes of code 
(printf uses >5k!)

*/

#include <stdarg.h>
#include "../src/main.h"
#include "../src/thprintf.h"





int thprintf(char *string, ...)
{
  va_list tag;
  int pointer=0, num_avaiable=0,  i=0, j=0;
  char char_parse=0, *char_pointer=0;
  signed int int_tmp=0, int_tmp2=0;

  va_start(tag, string);

  do
  {
    char_parse = string[pointer];    // get char


    if(char_parse == '%')
    {
      pointer++;
      char_parse = string[pointer];

      switch(char_parse)
      {
        case 'i':
        {
          int_tmp = va_arg(tag, int);
          num_avaiable=0;
          j=1000000;

          if(int_tmp <0)
          {
            fputc('-', 0);
            int_tmp*=(-1);
          }

          for(i=6; i>0; i--)
          {
            j/=10;
            int_tmp2 = int_tmp / j;
            if((int_tmp2) || (num_avaiable))
            {
              num_avaiable=1;
              fputc(((int_tmp2))+48, 0);
              int_tmp%=j;
            }
          }
          if(!num_avaiable) fputc('0', 0);    // Null ausgeben


        } break;

        case 'c':
        {
          fputc((char)va_arg(tag, int), 0);

        }break;

        case 's':
        {
          char_pointer = va_arg(tag, char*);

          while(*char_pointer)
          {
            fputc(*char_pointer, 0);
            char_pointer++;
          }
          break;

        }
      }
    } // end if '%'

    else if(char_parse == '\\')
    {
      pointer++;
      char_parse = string[pointer];

      switch(char_parse)
      {
        case 'n': fputc('\n', 0);
          break;

        case 't': fputc('\t', 0);
          break;
      }
    } // end if '\'


    else fputc(char_parse, 0);
    pointer++;

  } while(char_parse);

  va_end(tag);

  return(0);
}


von Joe (Gast)


Lesenswert?

Bin erstaunt das der Keil so etwas nicht in der LIB hat, ist beim SDCC 
standard, siehe printf_small, printf_tiny ...

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hi,

ich weiss nicht, obs in der Keil so was gibt (mal schaun), aber das ist 
sicher nicht <300 byte gross ;-))

von Joe (Gast)


Lesenswert?

Bezeichnung SDCC ist printf_tiny (ca. 300 Byte). Kannst dir ja die LIB 
mal ansehen.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hi,

danke für den Tipp.

Oki, das Ding ist in asm geschrieben, da kann ich mit der C-Ftk. nicht 
mithalten grins

Dafür ist meins sehr leicht erweiterbar und anpassbar ;-)


Greetz,
th.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hi Leutz,

mittlerweile bin ich auf 256 Bytes runter...

#include <stdarg.h>
#include "../src/main.h"
#include "../src/thprintf.h"

int thprintf(char *string, ...)
{
  va_list tag;
  int i=0;
  char *pointer=0;
  signed int int_tmp=0;

  va_start(tag, string);

  do
  {
    if(*string == '%')
    {
      switch(*(++string))
      {
        case 'i':
        {
          int_tmp = va_arg(tag, int);
          pointer=(void*)0;  //Pointer as marker

          if(int_tmp <0)
          {
            fputc('-', 0);
            int_tmp*=(-1);
          }

          for(i=MAX_NUM_DEC; i; i/=10)
          {
            if((int_tmp/i) || (pointer))
            {
              pointer=(void*)1;
              fputc((int_tmp/i)+48, 0);
              int_tmp%=i;
            }
          }
          if(!(pointer)) fputc('0', 0);    // Null ausgeben (Zahl = 0)

        } break;

        case 'c':
        {
          fputc((char)va_arg(tag, int), 0);
        } break;

        case 's':
        {
          pointer = va_arg(tag, char*);

          do
          {
            fputc(*pointer, 0);
          } while(*pointer++);
          break;
        }
      }
    } // end if '%'

    else if(*string == '\\')
    {
      switch(*(++string))
      {
        case 'n': fputc('\n', 0);
          break;

        case 't': fputc('\t', 0);
          break;
      }
    } // end if '\'

    else fputc(*string, 0);

  } while(*(++string));

  va_end(tag);

  return(0);
}


------------------------------------------------------------------------

Hab versucht, das noch weiter zu schrumpfen, bin dabei aber leider 
wieder auf 292 bytes gekommen.
Aber ich find die Lösung so böse-lustig, dass ich sie hier 
veröffentlichen möchte:

#include <stdarg.h>
#include "../src/main.h"
#include "../src/thprintf.h"

int thprintf(char *string, ...)
{
  va_list tag;
  int i=0;
  int *pointer=0;

  va_start(tag, string);

  do
  {
    if(*string == '%')
    {
      switch(*(++string))
      {
        case 'i':
        {
          //int_tmp = va_arg(tag, int);
          *pointer = va_arg(tag, int);

          if(*pointer <0)
          {
            fputc('-', 0);
            (*pointer)*=(-1);
          }

          // führende Nullen abtrennen
          for(i=MAX_NUM_DEC; i; i/=10)
            if(*pointer/i) break;


          for(; i;)
          {
            if((*pointer/i))
            {
              fputc((*pointer/i)+48, 0);
              *pointer%=i;
            }
            else fputc('0', 0);
            i/=10;
          }

        } break;

        case 'c':
        {
          fputc((char)va_arg(tag, int), 0);
        } break;

        case 's':
        {
          pointer = (int*) va_arg(tag, char*);

          do
          {
            fputc(*pointer, 0);
          } while(*pointer++);
          break;
        }
      }
    } // end if '%'

    else if(*string == '\\')
    {
      switch(*(++string))
      {
        case 'n': fputc('\n', 0);
          break;

        case 't': fputc('\t', 0);
          break;
      }
    } // end if '\'

    else fputc(*string, 0);

  } while(*(++string));

  va_end(tag);

  return(0);
}


Vllt sind für den ein oder anderen ein paar anregungen drin.


Greetz,
Th.

PS: Ich liebe solche spielchen mit C ;-)
Nu bin ich erst mal am ende ... hat jemand lust, weiterzumachen ? Her 
damit grins

von Random .. (thorstendb) Benutzerseite


Lesenswert?

So,

vorläufige Endversion.
180Byte ROM und 4Byte RAM mit Keil (-O3, oben war -O0).


// Th printf

/*
Author: Thorsten de Buhr
mail: thorsten@lasertechnix.de

Use:
Use is free, could run or not  ;-)

U may change every printf in cour code to thprintf, the rest is the 
same.

U may use:
%i, %s, %c
\n, \t

More is not implemented now.

*/

#include <stdarg.h>
#include "../src/main.h"
#include "../src/thprintf.h"





int thprintf(char *string, ...)
{
  va_list tag;
  int i=0;
  int *pointer=0;
  signed int int_tmp=0;


  va_start(tag, string);

  do
  {
    if(*string == '%')
    {
      switch(*(++string))
      {
        case 'i':
        {
          int_tmp = va_arg(tag, int);

          if(int_tmp <0)
          {
            fputc('-', 0);
            int_tmp=-int_tmp;
          }


          pointer = (int*)int_tmp;
          for(i=MAX_NUM_DEC; i; i/=10)
          {

            if((int)pointer/i)
            {
              fputc((int_tmp/i)+48, 0);
              int_tmp%=i;
            }
          }
        } break;

        case 'c':
        {
          fputc((char)va_arg(tag, int), 0);
        } break;

        case 's':
        {
          pointer = (int*)va_arg(tag, char*);

          do
          {
            fputc(*pointer, 0);
          } while(*pointer++);
        } break;
      }
    } // end if '%'

    else if(*string == '\\')
    {
      switch(*(++string))
      {
        case 'n': fputc('\n', 0);
          break;

        case 't': fputc('\t', 0);
          break;
      }
    } // end if '\'

    else fputc(*string, 0);

  } while(*(++string));

  va_end(tag);

  return(0);
}


Greetz,
th.

von Peter D. (peda)


Lesenswert?

Thorsten Db wrote:

> Nu bin ich erst mal am ende ... hat jemand lust, weiterzumachen ? Her
> damit *grins*


Z.B. hier:

Beitrag "Zahlenausgabe"


Peter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.