Int8_t/int16_t are 32bit

Hi, aren't these types supposed to guarantee their respective sizes? For some reason they are defined and report correct sizes with sizeof() but when used they are 32bit. Hilariously compiler report overflow warnings correctly too :smiley:

int8_t x = -320;
// warning: overflow in implicit constant conversion [-Woverflow]
int16_t y = -1;
int32_t z = -1;


Serial.println(sizeof(int8_t));
Serial.println(sizeof(int16_t));
Serial.println(sizeof(int32_t));

Serial.println(x, HEX);
Serial.println(y, HEX);
Serial.println(z, HEX);

Output:

17:35:33.934 -> 1
17:35:33.934 -> 2
17:35:33.934 -> 4
17:35:33.934 -> FFFFFFC0
17:35:33.966 -> FFFFFFFF
17:35:33.966 -> FFFFFFFF

The arduino print statements appears to perform integer promotion.

1 Like

The source code for the print statements show that the data type printed is long no matter the (numeric) data type printed.
...\Arduino 1.8.19\hardware\arduino\avr\cores\arduino\Print.cpp

size_t Print::print(unsigned char b, int base)
{
  return print((unsigned long) b, base);
}

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

3 Likes

You are seeing what the print command does to numbers. There are many questions and dislikes of this feature/bug in the print command especially when printing HEX. The first in the decimal print out are correct. The HEX printouts are correct as the print command defaults to 32 bits on HEX numbers. Try positive numbers for x, y, z. This link may help: sizeof() - Arduino Reference

You are seeing what the print command does to numbers
There are many questions and dislikes of this feature/bug in the print command

Ah, wasn't expecting Arduino library to have this kind of inconsistency. Thanks for the help.

  uint8_t x = 255;
  int8_t y = -1;
  
  Serial.println(x, BIN);
  Serial.println(y, BIN);
  Serial.println(x, HEX);
  Serial.println(y, HEX);
18:56:59.173 -> 11111111
18:56:59.173 -> 11111111111111111111111111111111
18:56:59.220 -> FF
18:56:59.220 -> FFFFFFFF

Is there any way to fix this? The fact that serial monitor omits 0's for no reason is really annoying.

If you mean omitting the leading zeros - is not this a typical behaviour to any print command?

To my annoyance, (s)printf() doesn't do binary as far as I can see. Would be really useful sometimes to print binary with leading zeros. Certainly more useful than octal, which hasn't been used much since before the time of the "terrible lizards", but you can print octal with leading zeros :roll_eyes:

For me, it would be useful to print binary with leading zeros when you need a quick easy way to visualise data which is a bitmap rather than numeric data, like a character or symbol to be printed to an LCD/OLED/LED matrix or 7/14 segment display.

Here is a way to print leading zeros if desired. Can be expanded for larger data types.

// print data in binary with leading zeros

byte data;
char buffy[] = {'0','0','0','0','0','0','0','0','\0'};


void setup()
{
  Serial.begin(9600);
  data = 0x25; 
  for(int n=0; n<8; n++)
  {
   bitRead(data,n) ? buffy[7-n]='1' : buffy[7-n]='0';
  }
  Serial.println(data);
  Serial.println(buffy);  
}

void loop()
{    
}

I wrote this when I was testing something to do with binary data and saved it as PrintBin.h

It allows binary printing of an integer value of any type with leading zeroes with or without a following linefeed and with the printed values split into bytes or not

#include <Arduino.h>

template <typename varType>
void printBinBase(varType var, boolean splitBytes = false, boolean newLine = false )
{
  for (int bit = (sizeof(var) * 8) - 1; bit >= 0; bit--)
  {
    Serial.print( var >> bit & 1);
    if (splitBytes)
    {
      if (!(bit & 7))
      {
        Serial.print(" ");
      }
    }
  }
  if (newLine)
  {
    Serial.println();
  }
}

template <typename varType>
void printBin(varType var)
{
  printBinBase(var, false, false);
}

template <typename varType>
void printBinln(varType var)
{
  printBinBase(var, false, true);
}

template <typename varType>
void printBinBytes(varType var)
{
  printBinBase(var, true, false);
}

template <typename varType>
void printBinBytesln(varType var)
{
  printBinBase(var, true, true);
}

I thought that it would come in useful but have hardly ever used it !

Hi @PaulRB,

actually you can do this:

void DecToHex(int Value) {
    char *buf = new (char);
    sprintf(buf, "%0.4X", Value);
    Serial.println(buf);
}
  • Restriction: It only returns the HEX value of the two least significant bytes (even if you change int to long).
  • "%0.4X" makes sure you get capital letters and it is formatted to four characters with leading zeros

Anyway it should be no big issue to use sizeof() to adopt it to 4 or 8 byte data ...

P.S.: This works (but is probably not the best way to do it ... :wink: )

void DecToHex(long Value, int noOfBytes) {
  char buf0[5];
  char buf1[5];
  char format[] = "%0.4X";
  if (noOfBytes < 2) {
    format[3] = '2';
  }
  sprintf(buf0, format, Value);
  if (noOfBytes > 2) {
    sprintf(buf1, format, Value >> 16);
    Serial.print(buf1);
  }
  Serial.println(buf0);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Start");
  byte x = 0xFF123456;
  DecToHex(x, sizeof(x));
  int y = 0xFF123456;
  DecToHex(y, sizeof(y));
  long z = 0xFF123456;
  DecToHex(z, sizeof(z));
}


void loop() {
  // put your main code here, to run repeatedly:
}

See https://wokwi.com/projects/371158393938611201

@groundFungus @UKHeliBob thanks guys, but it wasn't a cry for help, be assured I have my favourite ways of printing the binary data in the way I want, already memorised. My point was it would be great if printf() would just do it, like it does for decimal or hex, so I don't have to do anything. For example

Serial.printf("%08b", myByte);

@ec2021 maybe I confused you somehow, sorry about that. I want printf() in binary. I know it works great in hex.

Serial.printf() isn't available on all cores I thought?

In any event, for printing hex, it's bloated AF. I got so fed up with the lousy output or unacceptable bloat for the insanely common - and also much easier for computers to do than everything else that functions like that output) that my cores have printHex() which does leading zeros - it's a bunch of functions to take different datatypes and then call printHex(uint8_t);, including swapping of bytes to reverse endianness (mainly for applications where you've got bytes-in-order-stored, and you're want to read larger datatypes made up of those - the human brain has the wrong endianness to read them natively). and it can take pointers to easily dump the contents of the whole extended IO block dedicated to a peripheral when debugging. And it's considerably smaller than Serial.print() or Serial.printf().

One could do a similar thing for binary and also be very flash efficient. I basically never want to print binary, so I haven't done it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.