You are likely wondering what are uint8_t, uint16_t, uint32_t and uint64_t.
That's a good question. Because it could be really helpul!
It turns out that they are equal respectively to: unsigned char, unsigned short, unsigned int and unsigned long long.
But what are ranges of all these types?
Let's test it in this C type tutorial.
We're going to use a variable called testValue equal to 0xFFFFFFFFFFFFFFFF.
Notice that 0xFFFFFFFFFFFFFFFF is the same as 18,446,744,073,709,551,615 and this is the maximum value possible for an unsigned long long, depending on your processor architecture (as gineera said in its comment).
It's not so easy to understand all these things, but keep trying, it will be clearer after the end of this tutorial. At least, I hope it.
In the code part we will see that the number8 variable has a result of 255.
Why? Because 255 is the maximum value of an unsigned char or an uint8_t.
So if we put a value of 256, our result would be 0.
Indeed, after 255 we go back to 0.
For example if we added +1 for each number below, we'd have:
0 (First value of a char or 1 byte) 1 2 3 ... 250 251 252 253 254 255 (Max value of a char or 1 byte) 0 (First value of a char or 1 byte) 1 2 3 ... until 255 (Max value of a char or 1 byte) 0 1 2 3 ... until 255 (Max value of a char or 1 byte) 0 1 2 3 and so on.
So we won't be able to have a value of 256 in a char (or a byte).
If we wanted to have a such value, we would have to use another type, for example an unsigned short or an uint16_t equal to 2 bytes or 16 bits.
Wow, this is still confuse? Let's continue!
Indeed, with an unsigned short, we will be able to use this type up a value of 65535 in decimal
or 0xFFFF in hex.
But in our example, we're going to use a huge value: 18,446,744,073,709,551,615.
And what we'll have will be the max value of each type!
Because this huge value is the maximum value of an unsigned long long.
So every type is set at the maximum value because they are a multiple of each maximum.
2^2 = 4 2^4 = 16 2^8 = 256 2^16 = 65536 2^32 = 4294967296 2^64 = 18446744073709551616
OK, but why the maximum value of a byte is 255 and not 256?
Because (2^8) - 1 = 256 - 1 = 255.
Indeed, our first value is 0 and not 1.
So the second is 1, the third is 2, and so on.
Thus, our last value is 255.
// testValue unsigned long long testValue = 0xFFFFFFFFFFFFFFFF; // 18446744073709551615 // 1 byte -> [0-255] or [0x00-0xFF] uint8_t number8 = testValue; // 255 unsigned char numberChar = testValue; // 255 // 2 bytes -> [0-65535] or [0x0000-0xFFFF] uint16_t number16 = testValue; // 65535 unsigned short numberShort = testValue; // 65535 // 4 bytes -> [0-4294967295] or [0x00000000-0xFFFFFFFF] uint32_t number32 = testValue; // 4294967295 unsigned int numberInt = testValue; // 4294967295 // 8 bytes -> [0-18446744073709551615] or [0x0000000000000000-0xFFFFFFFFFFFFFFFF] uint64_t number64 = testValue; // 18446744073709551615 unsigned long long numberLongLong = testValue; // 18446744073709551615
Now you are able to handle bits and bytes like a professional.
Well done, you've made it.
Comments
gineera (not verified)
Wednesday, September 18, 2013 - 11:48pm
Permalink
Note that the 'fixed-size'
Note that the 'fixed-size' types (int16_t etc) are NOT always directly equivalent to the standard C types given above (short etc) - it depends on the processor platform and compiler - that is why the fixed types were more recently introduced.
On a desktop 32-bit PC an int would be 32-bits; on an 8-bit micro both int and short are normally 16-bit. If the data size is critical (eg a set of bit flags) always use the fixed-size types.
Craig B. (not verified)
Monday, May 24, 2021 - 7:04pm
Permalink
They're not even necessarily
They're not even necessarily equivalent to *any* of the "standard C types", since the u?intN_t types must be exactly the number of bits as stated, with no padding bits. The signed types (intN_t) must also use two's complement representation. The normal integer types have no such guarantees.
Mi-K
Thursday, September 19, 2013 - 8:14pm
Permalink
Dear Gineera,
Dear Gineera,
You're absolutely right!
Indeed, for example on a 16-bit microprocessor we have as maximum values:
If you had an int with 32767 as value and added just 1, it would become -32768 because after 32767 we go back to the first value of an int, in our case -32768.
Each +1 added will go from -32768 to 0 and 0 to 32767.
It's not the case for an unsigned int because it starts from 0 and there is so no negative value. So the max is 65535 and if we had +1, we would go back to the first value, 0!
Thank you for your comment.
Raju (not verified)
Friday, January 2, 2015 - 8:32am
Permalink
thanks for important info.
thanks for important info.
monark (not verified)
Tuesday, August 19, 2014 - 10:47am
Permalink
hi thanks! :)
hi
thanks! :)
Steve (not verified)
Thursday, August 21, 2014 - 2:56am
Permalink
Dude, I don't know why, but
Dude, I don't know why, but it's so hard to find someone who can actually explain the C int types in such a simple way.
From a C noob, thanks man. :)
Aks (not verified)
Thursday, February 5, 2015 - 7:31pm
Permalink
thanks!! so well explained...
thanks!! so well explained...
Josh (not verified)
Tuesday, February 24, 2015 - 11:20pm
Permalink
Thank you for the explanation
Thank you for the explanation and illustration.
Ken (not verified)
Saturday, July 11, 2015 - 9:38pm
Permalink
A clear explanation but it
A clear explanation but it might help to add that each of those F's above is actually 1111 in your computer, so that 255 is 11111111 and testValue is 64 1's. For a full lesson google "counting in binary" but the short answer is 11111111 rolls over to 00000000 just as 99 would become 00 if a calculator only had two digits.
Finally, to ensure the most compact and fastest code, always use the smallest representation you can. So, if a counter can only go to 85 (say) then uint8_t is appropriate. Of course, you never want a uint8_t to inadvertently roll over to zero as you'll code will break for sure.
Mob (not verified)
Wednesday, August 2, 2017 - 9:26pm
Permalink
The fastest code is often
The fastest code is often aligned code, so using the smallest sizes for things is not always the best way. Also padding in structs and classes when using different sizes can bloat your types, so it does not mean using the smallest sized attributes will be translated to your assembly. Making sure you organize diff size atts in your header files AND using min size types is a good thing. :-)
Elie (not verified)
Tuesday, October 13, 2015 - 10:58am
Permalink
Thank you. :]
Thank you. :]
Miguel Moreira (not verified)
Monday, November 30, 2015 - 12:44am
Permalink
Thank you very much!
Thank you very much!
Manikyam (not verified)
Monday, January 4, 2016 - 12:09pm
Permalink
Thanking your explanation
Thanking your explanation about numbering concepts, so very useful this concepts to every one
yanie (not verified)
Wednesday, January 27, 2016 - 6:00am
Permalink
thank you for your
thank you for your explanation. i try to search about it in many time and find your explanation. it's so usefull. thank you very much :')
madhukar (not verified)
Saturday, February 27, 2016 - 1:39pm
Permalink
Sir what is the meaning of
Sir what is the meaning of last char ('t') in 'uint16_t ' or in 'uint8_t'.
Mi-K
Tuesday, March 1, 2016 - 6:00pm
Permalink
Hello,
Hello,
"_t" stands for "type" or made from a typedef.
I think it's like that by convention.
Anonymous (not verified)
Thursday, July 7, 2016 - 3:12am
Permalink
Thank You!!! Great reading
Thank You!!! Great reading but the "t" was bothering me!!! :-)
sunil (not verified)
Saturday, July 16, 2016 - 6:26am
Permalink
Hi sir ,
Hi sir ,
nice topic you explain please can you explain uintptr and int *ptr difference.
Mi-K
Saturday, July 16, 2016 - 7:33pm
Permalink
Hello sunil,
Hello sunil,
The main difference between:
is that "uint" is an unsigned integer.
It means that this is a number from 0 to +4,294,967,295.
Where as a "int" is from -2,147,483,648 to +2,147,483,647.
The first cannot be a negative one, the second can.
So when you use "uint *ptr" means that your pointer is pointing on a number from zero to +4,294,967,295.
And for "int *ptr", it means that your pointer is an adress where the number is potentially a negative number, from -2,147,483,648 to +2,147,483,647.
To resume, the value of the integer in the first example is positive, the second is maybe negative.
The main goal of using a "unsigned int" is that you can store a value until 4 billion with no problem, where in the second example you can store "only" a number of 2 billion.
I hope it helps.
jlong29 (not verified)
Wednesday, August 31, 2016 - 8:32am
Permalink
I think +2,147,483,648 should
I think +2,147,483,648 should be +2,147,483,647
Mi-K
Saturday, September 3, 2016 - 8:27pm
Permalink
Thank you jlong29,
Thank you jlong29,
I corrected it.
omkar (not verified)
Tuesday, July 19, 2016 - 1:30pm
Permalink
But pointer always contain
But pointer always contain address and how address can be a negative value ?
Mi-K
Tuesday, July 19, 2016 - 8:29pm
Permalink
Hello omkar,
Hello omkar,
A pointer is an address.
At this address there is a value.
This value can be negative.
Maria (not verified)
Tuesday, December 6, 2016 - 6:34am
Permalink
While performing binary
While performing binary operations like addition or subtraction on uint16_t or uint32_t data types, does the execution happen bitwise in C?
For example, if I want to add 0xFF with 0x11, is it first converted into the form 11111111 + 00010001 and then added using the binary addition rules or is it done like simple addition of integers?
Mi-K
Tuesday, December 6, 2016 - 3:28pm
Permalink
Hello Maria,
Hello Maria,
I think it's the same as an addition or a subtraction.
Because in programming everything is, at the end, converted in binary.
vishal narayana raju (not verified)
Wednesday, December 21, 2016 - 2:08am
Permalink
thanks for the info
thanks for the info
Marcus (not verified)
Friday, March 3, 2017 - 7:05pm
Permalink
The choice of int for most
The choice of int for most compilers is defined by the data bus size of the target processor. This is why you will find that:
char 8 (int on an 8 bit processor)
short 16 (int on a 16 bit processor)
long 32 (int on a 32 bit processor)
long long 64 (int on a 64 bit processor)
And the size of a pointer will match the largest type that will fit the size of the address bus
What seems to be missing from this article is the place in C libraries where these typedefs are usually located...
meena (not verified)
Thursday, March 9, 2017 - 7:21pm
Permalink
sir can u please tell how can
sir can u please tell how can we print any array or any variable defined by uint8_t data type
Mi-K
Saturday, March 11, 2017 - 10:29am
Permalink
Hello meena,
Hello meena,
To display a uint8_t do the same as a int.
RR (not verified)
Wednesday, November 21, 2018 - 11:25am
Permalink
Hey!
Hey!
Like your way of explaining :D so human and caring <3
Aditya (not verified)
Saturday, October 8, 2022 - 5:51am
Permalink
Write the declaration of
Write the declaration of variable x that is an array of pointers to n memory blocks, where each memory block contains a 16-bit signed integer value.
given: const size_t n = 50;
Add new comment