%zu format specifier with C99 not working

224 Views Asked by At

I'm willing to print a size_t value using the %zu format specifier in my format string, however, I always get "zu" as an output, rather than the actual value in my size_t variable:

size_t val = 10;
printf("val: %zu\n", val);  // outputs "zu", not "10"

I've seen that for other people that faced a similar issue, the fix was to set the C standard to C99 or above.

I'm building my project with CMake, and I have the following line in it:

# Set the C standard to C11
set(CMAKE_C_STANDARD 11)

So, I'd assume that I'm good to go, but no, I'm still getting the same issue.

Could I be missing something?

I'm using the following stack:

  • CMake version 3.22
  • Cross compiling with the arm-none-eabi-gcc version 10.3.1 toolchain
  • compilation flags: -Os -g -ffunction-sections -fdata-sections -fno-common -fmessage-length=0 -mcpu=cortex-m4 -mthumb -mthumb-interwork -mlittle-endian -mfloat-abi=hard -mfpu=fpv4-sp-d16

I've also added the -std=c11 compilation option just in case. Still does not work.

3

There are 3 best solutions below

1
kokopelli On BEST ANSWER

The standard library (newlib) used in the toolchain (Arm GNU Toolchain 10.3.1 provided by arm) does not have the c99 I/O format support enabled. If _WANT_IO_C99_FORMATS is not defined, %zu cannot be used as a format specifier. You can compile your standard library with the --enable-newlib-io-c99-formats configuration to make it work.

3
KamilCuk On

Could I be missing something?

Newlib standard C library implementation you are using disables size_t and also long long in printf in its "nano" version.

You can test with:

$ printf "%s\n" "#include <stdio.h>" "#include <stdint.h>" 'int main() { printf("%td\n", (ptrdiff_t)1); }' | arm-none-eabi-gcc --specs=nano.specs --specs=rdimon.specs -xc -
$ ./a.out  # run with binfmt or arm-none-eabi-gdb simulator mode
td
0
chqrlie On

The format length modifier z is not supported by the C library used on your target system. Either it is too old and does not support C99 extensions, or it is purposely crippled to save some (rather small) amount of code and only supports %d, %u and %x. You should cast size_t values as (unsigned) and use %u:

size_t val = sizeof(int);
printf("val: %u\n", (unsigned)val);  // probably outputs "val: 4"