Why truncate leading zeros with Serial.print(i,BIN)?

Yes I've read every thread with system user insulting seasoned developers for asking this.
There is just no time in 45 years of experience I have ever needed a truncated binary output, but there are always problems when we read the bits with no leading zeros and I would have to literally count every 1 and 0 every time it outputs just to know if that was the MSB or which bit position is the first 1. I don't care about HEX because it's not too many digits to see quickly.

It is always used to see each flag in a byte or word. Example: Today I simply need to see if all 8 buttons work when I read from SPI. It was a relief there was already a simple option Serial.print(value, BIN) but you blew it!

Sure I can write my own code and you even say some ideas are too much code and it can be simple, but then why did you waste so much code in the Serial library because you had to write extra code just to truncate some of the bits?!

Once you have a field of 5 or more bits it becomes hard to keep track. That's why most experienced programmers display binary values in HEX.

Yes, It's annoying that the Print::print() does not allow for leading zeroes and that .print((char)-1, BIN) shows thirty two 1's. You can always write your own functions to format numbers in the style you like.

That's good info, I assumed it would be only 16 bits not 32 on the Uno but could that be good reason they decided to truncate zeros because they don't know what size is being passed in? To me the most important in the BIN function would be fixed width, but 32 bits is even more waste for an Uno.

Maybe my best solution is bitwize OR with 0x100 since it's easier to get used to ignoring the high bit that doesn't exist. I would have chosen two options like BIN8 and BIN16 but just 16 bits would satisfy more users than variable bit width (and could expand to 32 if a larger value was passed). I'm not asking for a change though, just understanding.

I avoid showing HEX when I'm demonstrating this because I'm the only one good at converting HEX to BIN in my head. I just wanted to show quickly that the switches are right and if 32 bits, would have still worked because it's just writing the output once on each line so each bit position stays alligned.

*I forgot to ask where is source code if I want to change it myself? First it seemed like would be inside the library folder.

Print.cpp is part of the "core" (and for newer cores, it's part of the "API", so something like: .../packages/arduino/hardware/avr/1.8.3/cores/arduino/Print.cpp or .../packages/arduino/hardware/samd/1.8.11/cores/arduino/api/

The printNumbers method does not trim the output string. It converts a number to the binary system by sequentially dividing by 2 and filling the string with digits from end to beginning. When the number becomes zero, it stops dividing and returns a pointer to the first character of the string.

do {
    char c = n % base;
    n /= base;
    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

The Print class has several different methods for int, unsigned int, long, unsigned long.

... \arduino-1.8.x\hardware\arduino\avr\cores\arduino
Print.h and Print.cpp

Yes. But the 'int' function just calls the 'long' function and the 'unsigned' function just calls the 'unsigned long' function. That's why .print(-1, BIN) calls the 'int' function but prints thirty-two 1's.

1 Like

Thanks, once I saw the source, I could see why it's not practical to be fixed width only for BIN/HEX. I wish it was explained a little different in the reference because I didn't realize you can use any base value not just defines like BIN. Say, try base 3 or 64 for educational purpose. I used to divide by base that way when I was younger and didn't know specific purpose or what base I would typically need.

Well I won't complain about that anymore.

After getting into robotics (I come from Motorola/Freescale) doing less RAM, I just made more specialized routines to deal with minimal RAM, registers, stack space, etc. My best BIN conversion in 8-bit assembly is rotate left 8 times using the sign bit to output 1 or 0.

1 Like

Wonderful. You can add your BIN conversion routine with a given number of digits to the Arduino libraries.

It's clear. But he asks why the function doesn't give a fixed number (16 or 32) of binary digits.

Boffin, the fact that passing int value always converts to long int is why it cannot know if only 16 bits was passed in when converting to base n.

What helps me however is that because dividing by base n makes the output automatically right justified, I could easily modify it to fill zeros to the left to make it fixed 8 or 16 bits if I wanted.

All of the integers (char, byte, int, unsigned, long, unsigned long) end up at this function:
size_t Print::printNumber(unsigned long n, uint8_t base)
How would this function decide how many digits to print? It pulls off low-order digits and adds them to the string until the result is zero. That is why there are no leading zeroes.

To allow for field width size you would likely need to add an argument to every level of the 'print' and 'println' functions for integers. That would mean that the "base" argument would be required before the "width" argument could be used. I don't think the changes would be very difficult but good luck getting the new feature included in the official Arduino libraries.

Of course, once you have allowed for fixed width output you will likely be asked for the option of leading blanks or leading zeroes. Might as well add that feature at the same time. Perhaps you could use a negative 'base' to indicate leading blanks.

Note: The signed numbers are currently handled by printing a '-' and then printing the absolute value of the integer. This means that the negative sign would be to the left of the leading blanks or zeroes. That can be solved by adding a 'sign' argument to 'printNumber()' to allow it to insert the '-' just to the left of the most significant digit if leading blanks have been selected.

What should happen if the field width is too narrow for all of the significant digits? Should the more significant digits just be ignored? Should the field be filled with '***' to indicate an overflow?

Your answer is obviously not addressed to me.
I have no problem with Serial.print() function.
If I am not satisfied with the Arduino functions, I write my own functions.

Yes john so I realized if I wanted the Print class to handle it I'd rather an overload with extra parameter(s) to just say the fixed width desired instead of detecting the width passed in.

You both are agreeing what I'm seeing too: Print class is a general purpose class and because I was being a fanatic about not increasing code size, it's better done in a specialized lib we only use if we care about that.

1 Like