3

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.

kokopelli
  • 208
  • 1
  • 7
  • Edit the question to provide a [mre]. – Eric Postpischil Aug 04 '23 at 15:27
  • 1
    Which compiler, which compiler version, which exact compiler options, what source code, how is it executed, on what platform, on which architecture, what C standard library implementation, what printf implementation? – KamilCuk Aug 04 '23 at 15:29
  • Are you trying to use it under MinGW? Not sure if anything changed recently, but there used to be a problem with this. https://stackoverflow.com/questions/68900199/how-to-get-mingw-gcc-to-recognize-the-zu-format-specifier-for-size-t – Eugene Sh. Aug 04 '23 at 15:30
  • I've edited my question to provide some more details on the compilation tools I'm using. @KamilCuk check my edited message, I hope I've listed everything. – kokopelli Aug 04 '23 at 15:42
  • @EugeneSh. nope, I'm using arm-none-eabi-gcc. But maybe worth mentioning I'm compiling from wsl. Might it affect this in any way? – kokopelli Aug 04 '23 at 15:43
  • Are you _sure_ you are not using any other flags? Check `cmake --build --verbose` or `make VERBOSE=1`. I am not 100% sure, but newlib may be just lacking %zu. My magic tells me you are using --specs=nano.specs. – KamilCuk Aug 04 '23 at 15:44
  • @KamilCuk I did the following: `cmake --build . --verbose --target all -j 8 > build_out.txt`, followed by `grep "nano.sp" build_out.txt`, and no line was found. I remember setting up the this compilation flags once because I had issue with my system calls, but removed it afternwards. I also cleaned cmake's cache, just to be sure there was no remaining from it left. I've seen your answer below, is the "nano" version enabled by default? Or do I have to force it somehow not to use the nano version? – kokopelli Aug 07 '23 at 08:52
  • 1
    `is the "nano" version enabled by default?` Could be. Take cmake out of the equation. I posted below how to test it. Post `arm-none-eabi-gcc -v` output and inpsect the verbose output with what it links. Yes, it is possible that the newlib version you are using was compiled in nano version. Also inspect specs files installed with the compiler. I am not aware how to not-force nano version. See nano.specs – KamilCuk Aug 07 '23 at 10:42

3 Answers3

2

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
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • And I guess `%td` would also be disabled (for printing `ptrdiff_t` values)? – Ian Abbott Aug 04 '23 at 16:52
  • 1
    Yes. `$ printf "%s\n" "#include " "#include " 'int main() { printf("%td\n", (ptrdiff_t)1); }' | arm-none-eabi-gcc --specs=nano.specs --specs=rdimon.specs -xc - && ./a.out` results in `td`. – KamilCuk Aug 04 '23 at 17:01
  • Thank you for your helpful answer. As mentioned in one of my comment above, no, I'm not using the nano spec of newlib. However, your input helped me a lot to understand a bit better what's going on here. I have installed the arm-none-eabi toolchain on ubuntu using the `sudo apt-get install arm-none-eabi-gcc` command. It all came in a package, and I believe the version of the newlib they include is missing the `--enable-newlib-io-c99-formats` configuration. I need to spend a bit more time on understanding how all thos configuration work, but I'll try to compile newlib with it on my side. – kokopelli Aug 07 '23 at 15:09
1

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"
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

The standard library (newlib) used in the toolchain (Arm GNU Toolchain 12.3.Rel1 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.

kokopelli
  • 208
  • 1
  • 7