datatypes bit depth

riodda

Well-known member
It really sounds like a silly question and it probably is but i think it will be helpfoul for coding newbies (like me) to create a small table to summarize the various datatypes bit depth for the teensy 3.0, i'm porting a sketch from arduino to teensy and i'm full of doubts about the bit depths difference between the arduino and the teensy.

Thanks !
 
On 32-bit ARM systems like Teensy 3.x/LC:

  • char, signed char, and unsigned char are 8 bits;
  • The plain char type is unsigned by default;
  • short and unsigned short are 16 bits;
  • int and unsigned int are 32 bits;
  • long and unsigned long are 32 bits;
  • pointers are 32 bits;
  • long long and unsigned long long are 64 bits;
  • float is 32 bits;
  • double is 64 bits;
  • long double is 64 bits.

On 8-bit AVR systems like Teensy 2.0, Arduino Uno, etc:

  • char, signed char, and unsigned char are 8 bits;
  • The plain char type is signed by default;
  • short and unsigned short are 16 bits;
  • int and unsigned int are 16 bits;
  • pointers are 16 bits;
  • long and unsigned long are 32 bits;
  • long long and unsigned long long are 64 bits;
  • float is 32 bits;
  • double is 32 bits (this violates ISO C/C++);
  • long double is 32 bits (this violates ISO C/C++).
 
I have several sketches that have been moved from a Nano and Mega to a Teensy 3.2. I've adopted the terminology intxx_t/uintxx_t to be sure it works on both boards. The value of xx can be 8, 16, 32, or 64.
 
helpful summary, thanks

Do long long and long double mean the same thing in ISO C/C++?
 
helpful summary, thanks

Do long long and long double mean the same thing in ISO C/C++?

long long (which is an integer type at least 64 bits) was not in the original ANSI C (C89) and ISO C90 standards. The next version of the C standard (C99) did have long long.

I don't have a copy of C++89, but long long is in the C++11 and C++14 standards.

long double (which is a floating point type that might have more precision and/or exponent range than double) was in the orignal C89/C90 standards. As I mentioned in my first reply, the AVR double does not meet the ISO C/C++ standards because it is only 32-bits.
 
Last edited:
Thanks !!! Very helpfoul I thinik this should be put someware in the teensy 3.x product details.
 
Added MM's post to the WIKI links list: Wiki-Coming-Please-link-worthy-posts

As Artic_Eddie notes in post #3 intxx_t/uintxx_t gives explicit well defined types, and float is the best supported type for Teensy floating point - single precision floating point on T_3.5 and T_3.6 is native and well emulated on the prior T_3's.
 
I have several sketches that have been moved from a Nano and Mega to a Teensy 3.2. I've adopted the terminology intxx_t/uintxx_t to be sure it works on both boards. The value of xx can be 8, 16, 32, or 64.

For variables that iterate over arrays, you want to use the size_t type, which is an unsigned type large enough to iterate over array indexes. On 64-bit systems, int is typically 32-bits, and the 64-bit system may need to issue extra instructions to do 32-bit arithmetic in 64-bit values. While on a 32-bit system like Teensy, you can use int or unsigned, it is a useful habit to get into in case your platform of choice changes over the years.

If you need a signed variant, there is ssize_t, which is the same size as size_t, but signed.

If you need integer types that are the same size as void * pointers, there are the intptr_t and uintptr_t types. On most systems void * is the same size as other object pointers, but there have been systems in the past that void * was a different size or representation than int *. And also, there have been systems where a pointer to a function is different than a pointer to an object.

If you want to use the largest integer type supported by the compiler, there are the intmax_t and uintmax_t types.

If you want a type that is at least <n> bits, but is fast, you would want to use int_fast<n>_t and uint_fast<n>_t (replace <n> with 8, 16, 32, or 64).

If you want a type that is at least <n> bits, but may be larger, you would want to use int_least<n>_t and uint_least<n>_t (replace <n> with 8, 16, 32, or 64).
 
Last edited:
If you need a signed variant, there is ssize_t, which is the same size as size_t, but signed.
It's a very lousy type, it's not even standard C or C++. It's defined by Posix:
<<< The type ssize_t is capable of storing values at least in the range [-1, SSIZE_MAX]. >>>

Don't use it, unless you need to interface with other code using it.
 
It's a very lousy type, it's not even standard C or C++. It's defined by Posix:
<<< The type ssize_t is capable of storing values at least in the range [-1, SSIZE_MAX]. >>>

Don't use it, unless you need to interface with other code using it.

While it isn't part of ISO C++, it is frequently useful to have a signed variant of size_t that is the same size. And given the Arduino libraries use newlib with also supports Posix, it should be safe to use.

As I said on 64-bit platforms, size_t is usually the preferred unsigned integral type, and ssize_t would be the preferred signed integral type.
 
While it isn't part of ISO C++, it is frequently useful to have a signed variant of size_t that is the same size.
But that's not what you are getting. It can be longer (quotes from "Open Group Base Specifications Issue 7"): "The wording is such that an implementation may either choose to use a longer type or simply to use the signed version of the type that underlies size_t. ..." It may or may not be able to represent size_t values: "It is recognized that some implementations might have ints that are smaller than size_t.".

The guaranteed negative range is -1. There is a macro for the positive range SSIZE_MAX, there isn't one for the negative range (SSIZE_MIN is missing).

IMO, intptr_t, ptrdiff_t or one of the int*_t types are a better choice (except when interfacing with code already using ssize_t).
 
As far as I see it from my uneducated view: Main intention to have ssize_t is the use as a return type to offer a size_t type return value with the addition of -1 to denote some error condition. Following that line of thought it would need to be 1 bit wider than size_t, but in the real world this poses all kinds of issues. One way around this is to use in-out parameters of size_t and have a dedicated return value for ok/error.
 
So many thanks !

On 32-bit ARM systems like Teensy 3.x/LC:

  • char, signed char, and unsigned char are 8 bits;
  • The plain char type is unsigned by default;
  • short and unsigned short are 16 bits;
  • int and unsigned int are 32 bits;
  • long and unsigned long are 32 bits;
  • pointers are 32 bits;
  • long long and unsigned long long are 64 bits;
  • float is 32 bits;
  • double is 64 bits;
  • long double is 64 bits.

On 8-bit AVR systems like Teensy 2.0, Arduino Uno, etc:

  • char, signed char, and unsigned char are 8 bits;
  • The plain char type is signed by default;
  • short and unsigned short are 16 bits;
  • int and unsigned int are 16 bits;
  • pointers are 16 bits;
  • long and unsigned long are 32 bits;
  • long long and unsigned long long are 64 bits;
  • float is 32 bits;
  • double is 32 bits (this violates ISO C/C++);
  • long double is 32 bits (this violates ISO C/C++).


:)
Just perfect !
 
It really sounds like a silly question and it probably is but i think it will be helpfoul for coding newbies (like me) to create a small table to summarize the various datatypes bit depth for the teensy 3.0, i'm porting a sketch from arduino to teensy and i'm full of doubts about the bit depths difference between the arduino and the teensy.

Thanks !

You can just ask the compiler, using sizeof().
Code:
void setup ()
{
  Serial.begin (...) ;
  Serial.printf ("char is %d bytes\n", sizeof(char)) ;
  ... etc etc
}
 
Yes, 32 bit variables have optimal performance on 32 bit ARM.

With 8 and 16 bit variables, the actual values are held in 32 bit registers. In some circumstances the compiler needs to add extra instructions to mask or sign extend the extra bits. Passing values to functions and return values are common cases.

Obviously 64 bit variables are slower because the operations are done with 32 bits at a time. Even with 64 bit double which is natively supported by the FPU in Teensy 4, the math happens at half the speed of 32 bit float.
 
i'm porting a sketch from arduino to teensy and i'm full of doubts about the bit depths difference between the arduino and the teensy.

Thanks !

You can always just write a sketch to ask the compiler directly, something like this:
Code:
void setup()
{
  Serial.begin (115200) ;
  Serial.printf ("sizeof int %i\n", sizeof(int)) ;
  Serial.printf ("sizeof long %i\n", sizeof(long)) ;
  ...
 
thanks paul, by you're explaining it sounds like the major advantage is on compiling. what about the run time?
32-bit variables can afford a stable operation? is it possible that using a non-32-bit variable can cause crushes in a certain way?
 
By "stuck", maybe you mean cause an ARM exception fault, which for all practical purposes stops your program from running? Or perhaps you meant something else?
 
To try answering now... as far as I know, uses of 8 and 16 bit variables always work. There aren't cases where using less than 32 bit would cause the processor to have an exception fault or otherwise stop.

Well, except for a couple caveats....

You will get a fault when making an illegal memory access. Teensy models differ in the type of illegal access they are able to detect. Teensy 4 detects the most type of problems, though the older ones will fault if you try a write to the flash, or access areas without any memory or peripheral.

You can get a fault or lockup if trying to access a peripheral which is disabled or powered off.

On Teensy LC, all 16 and 32 bit variables must be aligned to 16 or 32 bit memory boundaries. By default the compiler always aligns them, so usually unaligned access only happens if you do something like typecasting arbitrary integers to pointers. You will get a fault on Teensy LC if unaligned memory access is attempted. Teensy 3 & 4 do allow unaligned memory access, at least to normal memory. Some peripherals support it, others don't. I believe there is also a config bit somewhere in the ARM processor which disables the ability to access unaligned memory, which would give the same behavior as Teensy LC if you found and changed that setting.

But these cases are far outside the norm of regular programming.

Simply using 8 or 16 bit variables doesn't cause the CPU to fault or stop. ARM specifically designed it to be able to handle 8 and 16 bit variables.
 
Back
Top