mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik smartes printf


Autor: Random ... (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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);
}


Autor: Joe (Gast)
Datum:

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

Autor: Random ... (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

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

Autor: Joe (Gast)
Datum:

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

Autor: Random ... (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Random ... (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Random ... (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten Db wrote:

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


Z.B. hier:

Beitrag "Zahlenausgabe"


Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.