People would answer officialy like: conversions with capital letters like %C and %S (not %c and %s) print things in parsable formats by OCaml. The change of %b to %B followed this, since it prints booleans as true and false which are also OCaml parsable.
You can find a backstory here: http://caml.inria.fr/mantis/view.php?id=1438 . There was a branch which introduced this %B then changed the meaning of %b for binaries. The latter broke the backward compatibility therefore that part was rejected. As the result, today we have two conversions for booleans %B and %b.
The people coming up with the next C language standard are proposing new printf() format specifiers %b and %B, to output integers as binary literals, i.e. 0b00010110, the binary representation of 22.
The section of the Bash manual describing the builtin printf command references the manual for the external printf program, printf(1); which itself references the manual for the C function printf(), printf(3). The Bash builtin printf command supports a bunch of C-language printf() format specifiers, so they just direct you to that documentation to see how those work.
However, the Bash builtin printf supports additional format specifiers, beyond those supported by the C-language printf(). One of those is %b, which in the case of Bash's printf, currently "causes printf to expand backslash escape sequences in the corresponding argument in the same way as echo -e."
A number of people from the Austin Group, the people behind the POSIX specification, emailed in to the bug-bash email list, where Bash development discussion takes place, saying that they would like a new POSIX standard to change the mandated behavior of the %b format specifier used by the command-line printf command, whether that's an external program or the Bash builtin, to mirror the behavior of this format specifier as used by the C printf() function in the upcoming C standard. They are recommending %#s, signifying an alternative string format, to take over the duties of the current %b. They do seem to be saying that they'd only change the standard in this way if they get buy-in from shell authors, though.
Chet Ramey, the Bash maintainer, really wasn't having it:
I don't have a problem adding %#s. I have a problem with POSIX not seeing that the printf builtin is not a direct parallel to the library function and forcing an incompatible change.
So, do scripts you write or maintain use the %b printf format specifier? What's your take on all this?
Videos
The reason for the discrepancy in your results is that the Raspberry Pi C SDK uses a different C library than the one on your Ubuntu system. Specifically, the picolibc library is used by the SDK for code compiled for a Pico target system. This would explain why you get no errors or warnings when the target is a Pico.
OTOH, glibc is the C library used for compilations targeted for Ubuntu. This is a bit of a guess, but I can imagine that since the first version of glibc to support the %b format was 2.35 (the version on your Ubuntu system), there was some unsettled business between gcc and glibc that resulted in a warning. I say this because earlier versions of glibc (e.g. ver 2.31) and gcc (ver 10.2.1) produced an error instead of a warning upon seeing the %b conversion in printf, and compile without error or warning w/ glibc ver 2.36 and gcc ver 12.2.
The Raspberry toolkit uses a different C compiler and C library, and seems to support the %b format at runtime (binary output) and compiler time (no warning).
Conversely, on the Ubuntu host, your C library supports the %b format (including the # option) as shown on the output, but the C compiler does not and reports a compile time warning.
The gcc warnings for printf and scanf argument consistency are produced at compile time by the compiler built-in analyser. The compiler does not use the C library for this so it may report a problem where the C library does support an extended format.
This inconsistency should be fixed with a more recent version of gcc, so you should either upgrade your system or install a more recent version of gcc manually. You can also check the behavior of clang.
You can disable these warnings, but they are very useful to avoid stupid mistakes, so you should do this on a case by case basis with pragmas.
Hacky but works for me:
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
((byte) & 0x80 ? '1' : '0'), \
((byte) & 0x40 ? '1' : '0'), \
((byte) & 0x20 ? '1' : '0'), \
((byte) & 0x10 ? '1' : '0'), \
((byte) & 0x08 ? '1' : '0'), \
((byte) & 0x04 ? '1' : '0'), \
((byte) & 0x02 ? '1' : '0'), \
((byte) & 0x01 ? '1' : '0')
printf("Leading text "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(byte));
For multi-byte types
printf("m: "BYTE_TO_BINARY_PATTERN" "BYTE_TO_BINARY_PATTERN"\n",
BYTE_TO_BINARY(m>>8), BYTE_TO_BINARY(m));
You need all the extra quotes, unfortunately. This approach has the efficiency risks of macros (don't pass a function as the argument to BYTE_TO_BINARY) but avoids the memory issues and multiple invocations of strcat in some of the other proposals here.
Print Binary for Any Datatype
// Assumes little endian
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i = size-1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = (b[i] >> j) & 1;
printf("%u", byte);
}
}
puts("");
}
Test:
int main(int argc, char* argv[])
{
int i = 23;
uint ui = UINT_MAX;
float f = 23.45f;
printBits(sizeof(i), &i);
printBits(sizeof(ui), &ui);
printBits(sizeof(f), &f);
return 0;
}