Adding printf() to Print class

Hi,
I would like to be able to use formatted print for both Serial and LCD prints. I followed the path described in https://playground.arduino.cc/Main/Printf .

This suggested to change the Print.h files for AVR {installdir}/hardware/arduino/cores/arduino to include the code listed below at the end of the public: section in the Print.h file.

I did this to get many compilation errors:
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,

from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,

from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:232,

from C:\Users\klong\AppData\Local\Temp\arduino_build_651782\sketch\test_prtf.ino.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:93:9: error: ‘void Print::printf(const char*, …)’ cannot be overloaded

void printf(const char *format, …) {

^

This just a few, and suggests that I’ve missed something basic.

Below I listed the modified Print.h file.
What did I do wrong?
Thanks,
Keith

#ifndef Print_h
#define Print_h

#include <stdint.h>
#include <stddef.h>

#include "WString.h"
#include "Printable.h"

#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2

class Print {
   private:
       int write_error;
       size_t printNumber(unsigned long, uint8_t);
       size_t printFloat(double, uint8_t);
   protected:
       void setWriteError(int err = 1) {
           write_error = err;
       }
   public:
       Print() :
               write_error(0) {
       }

       int getWriteError() {
           return write_error;
       }
       void clearWriteError() {
           setWriteError(0);
       }

       virtual size_t write(uint8_t) = 0;
       size_t write(const char *str) {
           if(str == NULL)
               return 0;
           return write((const uint8_t *) str, strlen(str));
       }
       virtual size_t write(const uint8_t *buffer, size_t size);
       size_t write(const char *buffer, size_t size) {
           return write((const uint8_t *) buffer, size);
       }

       size_t printf(const char * format, ...)  __attribute__ ((format (printf, 2, 3)));
       size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));
       size_t print(const __FlashStringHelper *);
       size_t print(const String &);
       size_t print(const char[]);
       size_t print(char);
       size_t print(unsigned char, int = DEC);
       size_t print(int, int = DEC);
       size_t print(unsigned int, int = DEC);
       size_t print(long, int = DEC);
       size_t print(unsigned long, int = DEC);
       size_t print(double, int = 2);
       size_t print(const Printable&);

       size_t println(const __FlashStringHelper *);
       size_t println(const String &s);
       size_t println(const char[]);
       size_t println(char);
       size_t println(unsigned char, int = DEC);
       size_t println(int, int = DEC);
       size_t println(unsigned int, int = DEC);
       size_t println(long, int = DEC);
       size_t println(unsigned long, int = DEC);
       size_t println(double, int = 2);
       size_t println(const Printable&);
       size_t println(void);

virtual void flush() {/* Empty implementation for backward compatibility */}
#include <stdarg.h>
#define PRINTF_BUF 80 // define the tmp buffer size (change if desired)
  void printf(const char *format, ...) {
  char buf[PRINTF_BUF];
  va_list ap;
       va_start(ap, format);
       vsnprintf(buf, sizeof(buf), format, ap);
       for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines {
       if(*p == '\n')
       write('\r');
       write(*p);
                                                                           }
       va_end(ap);
                                       }
#ifdef F // check to see if F() macro is available
  void printf(const __FlashStringHelper *format, ...) {
   char buf[PRINTF_BUF];
   va_list ap;
   va_start(ap, format);
#ifdef __AVR__
vsnprintf_P(buf, sizeof(buf), (const char *)format, ap); // progmem for AVR
#else
vsnprintf(buf, sizeof(buf), (const char *)format, ap); // for the rest of the world
#endif
for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines {
       if(*p == '\n')
       write('\r');
       write(*p);
                                                                    }
       va_end(ap);
                                                      }
#endif
           };
#endif

try a wrapper: BufferedPrint from StreamLib has printf

  char buff[150];
  BufferedPrint bp(Serial, buff, sizeof(buff));

  bp.printf(F("Formated: %s;%c;%05d\r\n"), s, c, i);

  bp.flush();

Please edit your post to add code tags, as described in the "How to use this forum" post.

The code is much more portable and no library modifications are required, if you use sprintf() together with Serial.print() or LCD.print(). For example:

char buf[20];
int a=12;
int b=0x02FE;
sprintf(buf, "A: %d  B: 0x%04X", a, b);
Serial.println(buf);

For more reliability, use snprintf() instead.

Hi,
Thanks for your responses. I’ve tried both and still have a problem.
I would like to format print a number like 123.1235 to 123.124 (I think it will round up) that will maintain print space. Like %7.3f . If the number was 23.1235 the formatted print would be " 23.124"

Where is sprintf defined? Included the StreamLib for first response.

``/*
formatted print using printf() wrapper
*/

#include <stdarg.h>

#include “C:/electronics/Arduino/mylib/StreamLib-1.0.1/src/ChunkedPrint.h”
#include “C:/electronics/Arduino/mylib/StreamLib-1.0.1/src/CStringBuilder.h”
#include “C:/electronics/Arduino/mylib/StreamLib-1.0.1/src/FormattedPrint.h”
#include “C:/electronics/Arduino/mylib/StreamLib-1.0.1/src/BufferedPrint.h”
#include “C:/electronics/Arduino/mylib/StreamLib-1.0.1/src/StreamLib.h”

char buff[150];
// BufferedPrint bp(Serial, buff, sizeof(buff));

void setup() {
Serial.begin(9600);
double a_number=123.12345;
// bp.printf(F(“Formated: %8.4f\n”), a_number);
// bp.flush();
int num=123;
sprintf(buff,“Number is %d”,num);
Serial.println(buff);
}
void loop() {
}


sorry, defaul AVR printf functions do not support float. but I saw somewhere an implementation. google

You can add floating point support to sprintf() and printf() during linking, as described here http://forum.arduino.cc/index.php?topic=311154.0

I am the one that created that Printf page information on how to add printf() support to the Print class.

Where did you get the Print.h file you are working with? it already had printf() function declarations in it These two lines:

       size_t printf(const char * format, ...)  __attribute__ ((format (printf, 2, 3)));
       size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));

Unless you also added it (which is incorrect and not in the instructions). That is why you are getting the compilation errors.

Just keep in mind that once it is working, you won't be able to use it for floating point output, unless you go in and modify the linker options in the platform.txt file to link in the version of the code that supports floating point.

On a related note, many of the 3rd party cores come with a printf() method in their Print class. AVR Teensy 2.x, esp8266, chipkit/pic32, to name a few.

--- bill

Hi, OK using the your responses and stuff on line I can print a float:

/*
sprintf float example
*/
#include <stdio.h>
char buffer[80]={'\0'};
void setup() {
Serial.begin(9600);
Serial.print("");Serial.println("");
sprintf (buffer, "The value of PI to the fourth decimal place is %d.%04d", (int)PI, (int)((PI+.00005)*10000)%10000);
Serial.println(buffer);
             }
void loop() {
            }

Output: The value of PI to the fourth decimal place is 3.1416

I’m still confused about the use of printf, how do I attach this to Serial ? Not yet tried lcd.printf but
Serial.printf gives error

I'm still confused about the use of printf, how do I attach this to Serial ?

You don't, if you use the sprintf() method shown in reply #2.

It is possible to direct printf() output to the serial port, but that requires extra effort, not worth the trouble and again, not portable.

klong84: I'm still confused about the use of printf, how do I attach this to Serial ? Not yet tried lcd.printf but Serial.printf gives error

The function printf() and the printf method within a object like foo.printf() or Serial.printf() or lcd.printf() are different things. printf() the function is a C function provided by the AVR libC library. Getting printf() to work in an embedded environment like Arduino requires creating special linkage and helper routines which I also described on the Printf page as one of the possible methods to get xxprintf() support.

a printf method can be added to many objects like Serial and other objects that use the Print class by adding a printf method to the Print class. That is what was described on the Printf web page you referenced. You were encountering an issue because the Print.h you were using (the one you posted) already had declarations in it for prinf methods. It either had them before you started, in which case the printf method already existed and should work, or you added them and caused things to break because now there are multiple conflicting declarations for the printf methods.

Another alternative that has come along since I wrote the Printf page so many years ago is the PrintEx library. It offers a portable way to add a printf method, including floating point support, without having to modify any Arduino system files, libraries, or any of the Arduino tool configuration files like the AVR recipe file platform.txt Since it builds on the bundled Print class methods, it is a bit more efficient code and RAM wise than using sprintf() or adding a printf() method to the Print class. You can find that library in the Arduino library manager.

--- bill

you didn't try StreamLib? it is simpler then PrintEx

Hi,
I was not able to follow the 2nd reply, BufferedPrint bp(Serial, buff, sizeof(buff)); was not recognized, what library is to be included?
I really would like to add printf to arduino AVR print class. The code posted earlier to do this, is that copied from the playground describing how to to this. The modified print.h (print.h including modification to public section copied from playground and posted here earlier) was place locally at:
C:/‘Program Files (x86)’/Arduino/hardware/arduino/avr/cores/arduino/Print.h
I got many errors, also posted earlier.

printf is the best, using sprintf is so limiting; it will not work with %s, %e %f . And even if it did, it requires 2 instructions to complete.
How much space will printf use if added Serial?
How can I get printf added to Serial print class?
What are the problems re-directing stdin/out?
There are many ways to mimic printf, none that I know of are as comprehensive or straight forward.

/*
sprintf float example
*/
#include <stdio.h>
char buffer[80]={'\0'};
float FLT_OUT=0.0;
long KI[9]={1E0,1E1,1E2,1E3,1E4,1E5,1E6,1E7,1E8};
void fprt(float flt_in, int prc) {
                 float whl=(long)flt_in;
                 float prt=long((flt_in-whl+(0.5/KI[prc]))*KI[prc]);
                 prt=prt/KI[prc]; FLT_OUT=whl+prt;
                 return FLT_OUT;
                                 }
void setup() {
Serial.begin(9600);
Serial.print("");Serial.println("");
sprintf (buffer, "The value of PI to the fourth decmal place is %d.%04d\n", (int)PI, (int)((PI+.00005)*10000)%10000);
Serial.print(buffer);
String pi=String(PI,5); Serial.println(String("String  PI.5 ~ "+pi));
fprt(PI,6); pi=String(FLT_OUT,6); Serial.print(String("Flt-Str PI.6 ~ "+pi));
             }
void loop() {
            }

OUTPUT:

The value of PI to the fourth decmal place is 3.1416
String  PI.5 ~ 3.14159
Flt-Str PI.6 ~ 3.141593

klong84: I really would like to add printf to arduino AVR print class. The code posted earlier to do this, is that copied from the playground describing how to to this.

Not really. You have other stuff in Print.h file you posted and that is your issue. And I pointed this out in replies #6 and #9.

printf is the best, using sprintf is so limiting; it will not work with %s, %e %f . And even if it did, it requires 2 instructions to complete.

Again, there is a difference between using the printf() libC function and a printf() C++ method added to the Print class. You need to be clear which you are referring to.

However, functionally of printf() vs sprintf() all the xxprintf() routines, printf(), sprintf(), snprintf() as well as the printf() method added to the Print class as shown on the Printf page, all call the same lower level xxprintf() code so they all support the same formatting types and capabilities and will work the same with respect to formatting and formatting capabilities. i.e. there is no difference in formatting functionality between the functions. In fact the printf() method as shown on the Printf page is calling vsnprintf() which is simply a variation of sprintf().

To get any of the floating point formatting capabilities you have to use alternate compiler/linker options and to do that requires modifying the AVR platform.txt file.

How much space will printf use if added Serial?

So far there hasn't been any discussion about adding a printf() method to the HardwareSerial class which is what Serial uses. We have been talking about adding a printf() method to the Print class. If you are using the AVR and add the printf() method the way it was done on the Printf page, it will use up about 1.8k of code space if you call it assuming you are using the non floating point version. If you do the floating point version it will add another k or so. If you don't call the printf() method, it won't use any more code so adding the printf() method to the Print class will only add code to the f/w image if it is called.

How can I get printf added to Serial print class?

There is no such thing. To use a printf() method with the Serial object, you would want to add the printf() method to the Print class as described on the Printf page. It is easy and literally only takes about 1 minute to do. I just did it to verify that it still works with the latest IDE (version 1.8.5)

What are the problems re-directing stdin/out?

It isn't really that there are problems. It is just that it is a bit complicated since you have to create some linkage code for the output. This is described on the Printf page in the 3rd section: - Hooking into the embedded libc stdio support to make printf() work

It even includes examples for Serial and an lcd device.

In terms of code size there is no advantage of using the AVR printf() libC function with the linkage vs adding a printf() method to the Print class. My choice would be to add the printf() method to the Print class as it is easy and then it is available to any object that uses a library that inherits the Print class (there are many libraries that do this since it is the "normal" way character output is handled in Arduino libraries).

--- bill

klong84: I was not able to follow the 2nd reply, BufferedPrint bp(Serial, buff, sizeof(buff)); was not recognized, what library is to be included?

"StreamLib" is the name of the library. you can find libraries in IDE in menu Sketch -> Include library -> Manage libraries

Hi,
I do want printf added to AVR print class. I want printf to include floating point numbers.
I am at same point, errors after including the code suggested on arduinoplayground to end of the print class public section in the Print.h file. Yes Same place, I did same thing. What did I do wrong? The modified Print.h file
You point to 2 lines that are part of Print.h mods listed on playground.
The original Print.h file came from installdir, and the code on playground was added to it. Same as first time.
In the playgound prinf doc reads that all Print.h files will need alteration:

robot {installdir}/hardware/arduino/cores/robot
AVR(teensy) {installdir}/hardware/teensy/cores/teensy
teensy3 {installdir)/hardware/teensy/cores/teensy3
DUE {installdir}/hardware/arduino/sam/cores/arduino
chipKIT {installdir}/hardware/pic32/cores/pic32

I’m not using these only the AVR and only made changes to the Printf found there.
installdir: C:/‘Program Files (x86)’/Arduino/hardware/arduino/avr/cores/arduino

/*
 Print.h - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef Print_h
#define Print_h

#include <stdint.h>
#include <stddef.h>

#include "WString.h"
#include "Printable.h"

#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2

class Print {
    private:
        int write_error;
        size_t printNumber(unsigned long, uint8_t);
        size_t printFloat(double, uint8_t);
    protected:
        void setWriteError(int err = 1) {
            write_error = err;
        }
    public:
        Print() :
                write_error(0) {
        }

        int getWriteError() {
            return write_error;
        }
        void clearWriteError() {
            setWriteError(0);
        }

        virtual size_t write(uint8_t) = 0;
        size_t write(const char *str) {
            if(str == NULL)
                return 0;
            return write((const uint8_t *) str, strlen(str));
        }
        virtual size_t write(const uint8_t *buffer, size_t size);
        size_t write(const char *buffer, size_t size) {
            return write((const uint8_t *) buffer, size);
        }

        size_t printf(const char * format, ...)  __attribute__ ((format (printf, 2, 3)));
        size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));
        size_t print(const __FlashStringHelper *);
        size_t print(const String &);
        size_t print(const char[]);
        size_t print(char);
        size_t print(unsigned char, int = DEC);
        size_t print(int, int = DEC);
        size_t print(unsigned int, int = DEC);
        size_t print(long, int = DEC);
        size_t print(unsigned long, int = DEC);
        size_t print(double, int = 2);
        size_t print(const Printable&);

        size_t println(const __FlashStringHelper *);
        size_t println(const String &s);
        size_t println(const char[]);
        size_t println(char);
        size_t println(unsigned char, int = DEC);
        size_t println(int, int = DEC);
        size_t println(unsigned int, int = DEC);
        size_t println(long, int = DEC);
        size_t println(unsigned long, int = DEC);
        size_t println(double, int = 2);
        size_t println(const Printable&);
        size_t println(void);

 virtual void flush() {/* Empty implementation for backward compatibility */}
#include <stdarg.h>
#define PRINTF_BUF 80 // define the tmp buffer size (change if desired)
   void printf(const char *format, ...)
   {
   char buf[PRINTF_BUF];
   va_list ap;
        va_start(ap, format);
        vsnprintf(buf, sizeof(buf), format, ap);
        for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines
        {
                if(*p == '\n')
                        write('\r');
                write(*p);
        }
        va_end(ap);
   }
#ifdef F // check to see if F() macro is available
   void printf(const __FlashStringHelper *format, ...)
   {
   char buf[PRINTF_BUF];
   va_list ap;
        va_start(ap, format);
#ifdef __AVR__
        vsnprintf_P(buf, sizeof(buf), (const char *)format, ap); // progmem for AVR
#else
        vsnprintf(buf, sizeof(buf), (const char *)format, ap); // for the rest of the world
#endif
        for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines
        {
                if(*p == '\n')
                        write('\r');
                write(*p);
        }
        va_end(ap);
   }
#endif
            };

#endif

The errors:

ok> cat err1_add_after_virtual_void.txt
Arduino: 1.8.4 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,

                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,

                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:232,

                 from sketch\test_prtf.ino.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:93:9: error: 'void Print::printf(const char*, ...)' cannot be overloaded

    void printf(const char *format, ...)

         ^

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,

                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,

                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:232,

                 from sketch\test_prtf.ino.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:63:16: error: with 'size_t Print::printf(const char*, ...)'

         size_t printf(const char * format, ...)  __attribute__ ((format (printf, 2, 3)));

                ^

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,

                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,

                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:232,

                 from sketch\test_prtf.ino.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h: In member function 'void Print::printf(const char*, ...)':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:98:47: error: 'vsnprintf' was not declared in this scope

         vsnprintf(buf, sizeof(buf), format, ap);

                                               ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h: In member function 'void Print::printf(const __FlashStringHelper*, ...)':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:114:63: error: 'vsnprintf_P' was not declared in this scope

         vsnprintf_P(buf, sizeof(buf), (const char *)format, ap); // progmem for AVR

                                                               ^

exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I’m making the same mistake as the first time.
I’m not very familiar with c++, my base is in c and use awk/perl more often. Arduino is very good and would be so much better if printf was included in Serial.
floating point printf is also very important; floats and doubles only have 4 byte resolution (mega) and E format can close gaps in numbers. If you expect ranges of p,n,u,m,k,M,G ext.
Thanks for your help, I’m missing something in the Print.h mods. Once understood are floating point operations possible in printf()? If not how can I achieve this?

I will look into StreamLib, it maybe useful in serial communications used for processing, but my main goal is to be able to use printf for lcd and monitor printing.

Thanks again for your help.

from where are the lines

        size_t printf(const char * format, ...)  __attribute__ ((format (printf, 2, 3)));
        size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));

in your Print.h? they are not in original AVR core Print.h and they shouldn't be there for the printf patch from playground

klong84:
Hi,
I do want printf added to AVR print class. I want printf to include floating point numbers.
I am at same point, errors after including the code suggested on arduinoplayground to end of the print class public section in the Print.h file. Yes Same place, I did same thing. What did I do wrong?

Not quite sure but I have a guess (will get to that a bit later)

The modified Print.h file
You point to 2 lines that are part of Print.h mods listed on playground.

No they are not. Those two lines are not part of the Print.h modification. Look again.
You are adding/have added those lines in.

The original Print.h file came from installdir, and the code on playground was added to it. Same as first time.

From your IDE build output, you appear to be using IDE version 1.8.4
The AVR core Print.h that comes with the IDE does not contain the two lines I showed above.
You have done something that has added them.

In the playgound prinf doc reads that all Print.h files will need alteration:

robot {installdir}/hardware/arduino/cores/robot
AVR(teensy) {installdir}/hardware/teensy/cores/teensy
teensy3 {installdir)/hardware/teensy/cores/teensy3
DUE {installdir}/hardware/arduino/sam/cores/arduino
chipKIT {installdir}/hardware/pic32/cores/pic32

What it actually says is:

you will have to modify the Print.h header file for each architecture that you want to add printf() support into the Print class

That page was written MANY years ago. Since then chipKit, teensy, and Teensy3 now include the printf() method in their cores. So it is not longer needed for those cores.

My guess as to what is/has happened is that at some point you modified the AVR Print.h file by adding in those two printf() method declarations that you got from some other Print.h header file.
It was done either directly or through copying a Print.h from some other core into the AVR core.
Just a guess but that seems possible.

But like I’ve said several times already, your issue is those two printf() method declarations.
They are not part of the original Print.h file and somehow you added them and that is what is causing things to break.

— bill

Hi,
Wow, yes you are correct, I did (somehow) introduce those two printf lines in the Print.h file. The environment I’m working in needs a mouse click in the window in order to work in it, redhat another will use the cursor position alone to select the current window. I usually work with multiple windows (all on screen) and must have entered text in the wrong place and wrote it out in current dir.
Sorry, thanks for your patients.

From the get go I copied the installed Print.h in place to Print_org.h . Starting from there added the code found on the playground:

OK everything appears to work much like sprintf where only int’s can be used (no %e,%f,%s, or long).
The memory use monitored appeared to have a 20 byte local variable increase per unique variable print (small).

Odd thing noticed (also by chance):
Serial.printf(“Hello World!!!\n”);
Will compile and load (watching arduino rx/tx leds) but hangs in load phase (rx/tx leds quite again).
Serial.printf(“Hello World!\n”); Serial.printf(“Hello World!!\n”); is ok but 3 or more ! hang it.

OK success in making Serial.printf() look like sprintf.

What can be done to allow Serial.printf() to accept %s,%e,%f ?
I’m guessing that long/double use will be addressed with floating point numbers.
%s format not of great importance, but would be nice (C doesn’t allow passing Strings, not sure about C++ . In the past I wrote to a global a variable for String returns from functions)

Thanks again for your patients and help.

ok> cat Print_mod.h
/*
  Print.h - Base class that provides print() and println()
  Copyright (c) 2008 David A. Mellis.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef Print_h
#define Print_h

#include <inttypes.h>
#include <stdio.h> // for size_t

#include "WString.h"
#include "Printable.h"

#define DEC 10
#define HEX 16
#define OCT 8
#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar
#undef BIN
#endif
#define BIN 2

class Print
{
  private:
    int write_error;
    size_t printNumber(unsigned long, uint8_t);
    size_t printFloat(double, uint8_t);
  protected:
    void setWriteError(int err = 1) { write_error = err; }
  public:
    Print() : write_error(0) {}

    int getWriteError() { return write_error; }
    void clearWriteError() { setWriteError(0); }

    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) {
      if (str == NULL) return 0;
      return write((const uint8_t *)str, strlen(str));
    }
    virtual size_t write(const uint8_t *buffer, size_t size);
    size_t write(const char *buffer, size_t size) {
      return write((const uint8_t *)buffer, size);
    }

    // default to zero, meaning "a single write may block"
    // should be overriden by subclasses with buffering
    virtual int availableForWrite() { return 0; }

    size_t print(const __FlashStringHelper *);
    size_t print(const String &);
    size_t print(const char[]);
    size_t print(char);
    size_t print(unsigned char, int = DEC);
    size_t print(int, int = DEC);
    size_t print(unsigned int, int = DEC);
    size_t print(long, int = DEC);
    size_t print(unsigned long, int = DEC);
    size_t print(double, int = 2);
    size_t print(const Printable&);

    size_t println(const __FlashStringHelper *);
    size_t println(const String &s);
    size_t println(const char[]);
    size_t println(char);
    size_t println(unsigned char, int = DEC);
    size_t println(int, int = DEC);
    size_t println(unsigned int, int = DEC);
    size_t println(long, int = DEC);
    size_t println(unsigned long, int = DEC);
    size_t println(double, int = 2);
    size_t println(const Printable&);
    size_t println(void);

    virtual void flush() { /* Empty implementation for backward compatibility */ }

#include <stdarg.h>
#define PRINTF_BUF 80 // define the tmp buffer size (change if desired)
   void printf(const char *format, ...)
   {
   char buf[PRINTF_BUF];
   va_list ap;
        va_start(ap, format);
        vsnprintf(buf, sizeof(buf), format, ap);
        for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines
        {
                if(*p == '\n')
                        write('\r');
                write(*p);
        }
        va_end(ap);
   }
#ifdef F // check to see if F() macro is available
   void printf(const __FlashStringHelper *format, ...)
   {
   char buf[PRINTF_BUF];
   va_list ap;
        va_start(ap, format);
#ifdef __AVR__
        vsnprintf_P(buf, sizeof(buf), (const char *)format, ap); // progmem for AVR
#else
        vsnprintf(buf, sizeof(buf), (const char *)format, ap); // for the rest of the world
#endif
        for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines
        {
                if(*p == '\n')
                        write('\r');
                write(*p);
        }
        va_end(ap);
   }
#endif
};

#endif

klong84: Hi, Wow, yes you are correct, I did (somehow) introduce those two printf lines in the Print.h file. The environment I'm working in needs a mouse click in the window in order to work in it, redhat another will use the cursor position alone to select the current window.

How window selection works is configurable. If they are working differently, you have things configured differently.

OK everything appears to work much like sprintf where only int's can be used (no %e,%f,%s, or long).

It is beyond like, as it is all using the same code. This isn't like Windows where you have tons of code duplication and each can have slightly different modifications. In this case the code calls common code at the lower levels so the formatting will all be the same regardless of the upper level function called.

%s works just fine for C strings. Not sure what you are doing but it does work. Now if you are attempting to use %s with the Arduino proprietary F() macro which uses a proprietary C++ class to store things in FLASH, then no that isn't supported. AVR is a mess when it comes to const data because of the internal architecture which doesn't allow the processor to access flash directly. This limitation causes code to get really wonked up on the AVR whenever const data is involved. Other processors don't have this issue.

The AVR xxprintf() functions do support a proprietary %S formatting type which means that the pointer is flash address vs a RAM address. That can be used to print string that is stored in flash vs RAM.

--- bill

Hi Bill,
Thanks for your help, including printf into the Serial class (AVR). sprintf will not do everything desired (%f,%s,%e). I’ve started C++ programming and will able to move around better, soon.
Re-reading the posts made: I will check out buffered print employed in stream library (stream is also the base for Serial if I remember correctly). I didn’t notice %e format but use %f and %s format is useful.
I’ve already ran into some trouble with buffered print but will start a new post. I don’t see a way to end this one.
Should I do something to close this post as resolved?
Thanks,
Keith