Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: Adding Print class printf() format string vs arguments checking

  1. #1
    Senior Member
    Join Date
    Jan 2013
    Location
    Dallas, TX USA
    Posts
    111

    Adding Print class printf() format string vs arguments checking

    It is possible to get gcc to sanity check that the arguments handed to the Print class printf() functions match the format string.
    All you have to do is add a format attribute to their declarations in Print.h
    I created a github issue for this:
    https://github.com/PaulStoffregen/cores/issues/485

    It is nice to get the warnings for mismatched format strings and arguments.

    --- bill

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,027
    Quote Originally Posted by bperrybap View Post
    It is nice to get the warnings for mismatched format strings and arguments.
    Let's give this a try in 1.54-beta1 and see if the general consensus is "nice" or "extraneous".

    The main issue is int and long are both 32 bit on Teensy, but this format warning is pretty pedantic about wanting %d for int versus %ld for long. Lots of uint32_t are used, which are technically defined as unsigned long. My guess is a lot of needless warnings are going to appear.

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    12,685
    I've started using %ld ... painfully ... there was a sketch once on something that failed until I did that ...

  4. #4
    Senior Member
    Join Date
    Jan 2013
    Location
    Dallas, TX USA
    Posts
    111
    bummer.
    I just did some testing on linux and it has become a bit difficult to create portable printf format strings.
    We now have good portable types in <stdint.h> and now there are some portable printf format helper types/macros in <inttypes.h> but they are clunky.

    Then there are somewhat hidden types that are inconsistent across implementations
    Example, size_t and sizeof()
    There is no way to know what size these are. (sizeof() now returns a size_t instead of an int)
    Combine that with int and long int can be the same size and it starts to become difficult to write truly portable code.
    IMO, the printf() format checking is a bit broken as it is being too strict since it reports an issue for int vs long int when they are the same size.
    IMO, if they are the same size and the same signedness, then they are functionally the same so there should be no warning since they would be both be interpreted the same, and formatted the same.
    i.e. there is no stack frame issue since the two types are functionally the same.
    Maybe this is actually an issue that could/should be solved with <stdint.h> ?
    since if int and long int are the same then uint32_t could have been defined as unsigned int instead of a long unsigned int.

    There is no simple/easy answer since implementations can define things differently and behave differently.
    The only way to handle it is to use the format helper macros in <inttype.h> whenever types from <stdint.h> are used.
    For example:
    Code:
    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    uint32_t u32x = 1;
    uint64_t u64x = 1;
    
    int main(int n, char *argv[])
    {
            printf("uint32_t var : %"PRIu32"\n", u32x);
            printf("uint64_t var: %"PRIu64"\n", u64x);
    }
    but it is clunky.

  5. #5
    Senior Member
    Join Date
    May 2015
    Location
    USA
    Posts
    717
    > printf("uint32_t var : %"PRIu32"\n", u32x);

    Nice, thanks. But I tried it on a teensy and memory usage went way up.

  6. #6
    Senior Member
    Join Date
    Jan 2013
    Location
    Dallas, TX USA
    Posts
    111
    Quote Originally Posted by jonr View Post
    > printf("uint32_t var : %"PRIu32"\n", u32x);

    Nice, thanks. But I tried it on a teensy and memory usage went way up.
    Tried what? Compared to what?

    using PRIu32 vs using the a hard coded format type changing memory usage doesn't make sense to me.
    What exactly were you comparing.
    Can you show the two sketches?

    --- bill

  7. #7
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,210
    %zu works for size_t

  8. #8
    Senior Member
    Join Date
    Jan 2013
    Location
    Dallas, TX USA
    Posts
    111
    Quote Originally Posted by luni View Post
    %zu works for size_t
    Nice. I'm obviously behind on my C standards...

  9. #9
    Senior Member
    Join Date
    May 2015
    Location
    USA
    Posts
    717
    > Tried what? Compared to what?

    Agreed, wasn't clear.

    Serial.printf("%"PRIu32"\n", u32x);
    vs
    Serial.println(u32x);

    But the memory use is a printf() issue, not the use of "PRIu32".

    > it is clunky.

    Agreed - having to go find the type of a variable just to print it is very inconvenient.

  10. #10
    Senior Member
    Join Date
    Jan 2013
    Location
    Dallas, TX USA
    Posts
    111
    Quote Originally Posted by jonr View Post
    > Tried what? Compared to what?

    Agreed, wasn't clear.

    Serial.printf("%"PRIu32"\n", u32x);
    vs
    Serial.println(u32x);

    But the memory use is a printf() issue, not the use of "PRIu32".
    Obviously it will be larger since xxprintf() has lots of formatting capabilities whereas the Arduino Print class has very limited formatting capabilities.

    But back to the issue that Paul brought up, it is highly annoying that the printf() format checking routines are not smart enough
    to treat functionally equivalent types as equivalent.
    i.e. if unsigned int and unsigned long are the same then it seems a bit pedantic for printf() consider it an issue if not using the exact formatting code since in that case they both will behave identically.



    > it is clunky.

    Agreed - having to go find the type of a variable just to print it is very inconvenient.
    True, But at least if using types from <stdint.h> you will know the corresponding format macro from <inttypes.h>

    i.e. a uint32_t uses a format type of PRIu32
    vs trying to figure out whether to use the integer format or the long integer format which can change depending on implementation.

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,027
    Quote Originally Posted by bperrybap View Post
    But back to the issue that Paul brought up, it is highly annoying that the printf() format checking routines are not smart enough
    to treat functionally equivalent types as equivalent.
    i.e. if unsigned int and unsigned long are the same then it seems a bit pedantic for printf() consider it an issue if not using the exact formatting code since in that case they both will behave identically.
    Yes, "annoying" and "pedantic" are exactly the 2 words I would use.

    My current thinking is this feature does more harm than good and we should probably not use it (for a non-beta release) until a newer toolchain offers a better implementation.

    But I'm willing to listen to opinions on this. Now's the time to seriously discuss whether this belongs in the upcoming 1.54 release.

  12. #12
    Senior Member
    Join Date
    May 2015
    Location
    USA
    Posts
    717
    As I see it, it encourages people to write portable code and helps find errors in poor code from elsewhere.

    If someone doesn't like the "PRIu32" style, then there is:

    printf(" %u\n", (unsigned) uint32_variable);

    This makes it clear that one is willing to accept truncation (on some systems).
    Last edited by jonr; 10-24-2020 at 06:37 PM.

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,027
    I'm disabling the printf format warnings, at least for Teensyduino 1.54

    https://github.com/PaulStoffregen/co...10e54a4979eb7c

    Will reconsider after we've updated to a newer toolchain (likely to happen sometime in 2021). Hopefully future versions will bring less pedantic format warning?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •