sandeepmistry / arduino-nRF5

Arduino Core for Nordic Semiconductor nRF5 based boards
Other
890 stars 277 forks source link

inttypes are not handled correctly (PRIu8) #197

Open d00616 opened 6 years ago

d00616 commented 6 years ago

This sketch demonstrates printing to a string using defines of inttypes.h. The PRIu8 isn't interpreted correctly.

void setup() {
  Serial.begin(115200);
}

void loop() {
  char fmtBuffer[400];
  snprintf(fmtBuffer, sizeof(fmtBuffer), "hu=%hu PRIu8=%" PRIu8 " PRIu16=%" PRIu16 " PRIu32=%" PRIu32, 1, 1, 1, 1);
  Serial.println(fmtBuffer);
}

Output is: hu=1 PRIu8=hu PRIu16=1 PRIu32=1

d00616 commented 6 years ago

There is a notice in inttypes.h:

/* NOTICE: scanning 8-bit types requires use of the hh specifier
 * which is only supported on newlib platforms that
 * are built with C99 I/O format support enabled.  If the flag in
 * newlib.h hasn't been set during configuration to indicate this, the 8-bit
 * scanning format macros are disabled here as they result in undefined
 * behaviour which can include memory overwrite.  Overriding the flag after the
 * library has been built is not recommended as it will expose the underlying
 * undefined behaviour.
 */
sandeepmistry commented 6 years ago

What's the expected result of the sketch?

Toolchains used with this core are from https://launchpad.net/gcc-arm-embedded ...

sandeepmistry commented 6 years ago

Also, does this work as expected with SAMD based Arduino boards?

d00616 commented 6 years ago

The expected output is: hu=1 PRIu8=1 PRIu16=1 PRIu32=1

With a SAMD board the output is like expected. I think the reason is a difference in the toolchain. Gcc 5.2 vs. gcc 4.8.3

pbolduc commented 5 years ago

I was wondering if anyone had any addition information on this. I have created a couple of tickets because I cannot get MySensors to work correctly on my Moteino M0.

https://bugs.launchpad.net/gcc-arm-embedded/+bug/1836698

and on Platform IO (which is not the cause) https://github.com/platformio/platform-atmelsam/issues/70

Is it something wrong with the board definitions or compiler flags? I am looking for a work around.

#include <Arduino.h>

#undef PRIu8
#define PRIu8 "hu"

#ifdef MOTEINO_M0
#define Serial SerialUSB
#endif

void setup() {
  Serial.begin(9600);
  while (!Serial);

  char buffer[512];
  uint8_t value = 123;
  snprintf(buffer, sizeof(buffer), "value=%" PRIu8 "\n", value);

  Serial.print(buffer);

  Serial.print("PRIu8=");
  Serial.print(PRIu8);
}

void loop() {
}
pbolduc commented 5 years ago

Based on feedback from the gcc-arm-embedded issue, the problem is related to linking to the smaller newlib-nano library. See https://community.arm.com/developer/ip-products/system/b/embedded-blog/posts/shrink-your-mcu-code-size-with-gcc-arm-embedded-4-7

Libraries also need optimizing, because the libraries included in GCC ARM Embedded were not actually designed for MCU programming. Newlib, the C library in the toolchain, implements printf functions that are so complicated they require about 37K bytes of FLASH and 5K bytes of RAM to run a simple hello-world program. That's far too large for MCU programming where you might need printf functionality for debugging and logging purposes. The good news is that there is plenty of unnecessary "fat" in libraries that can be cut.

Newlib-nano cuts some features that were added after C89, which are believed to be rarely used in MCU programming. By limiting the format converter to the C89 standard, format string processing code in printf is greatly reduced.

To summarize, the newlib-nano can cut the size of hello-world programs by around 80%. In extreme cases for C++ programs, the size reduction could exceed 90%.