How does uint32_t guarantee 32 bits? - c++

In most implementations, I've seen uint32_t defined as
typedef unsigned int uint32_t;
But as I understand it ints are not always guaranteed to be 4 bytes across all systems. So if the system has non 4-byte integers, how does uint32_t guarantee 4?

An implementation is required to define uint32_t correctly (or not at all if that's not possible).
If unsigned int meets the requirements (32 bits wide, no padding bits), the implementation can define it as
typedef unsigned int uint32_t;
If it doesn't, but unsigned long does meet the requirements, it can define it as:
typedef unsigned long uint32_t;
Or it can use a different unsigned type if that's appropriate.
The <stdint.h> header has to be compatible with the compiler that it's used with. If you took a <stdint.h> header that unconditionally defined uint32_t as unsigned int, and used it with a compiler that makes unsigned int 16 bits, the result would be a non-conforming implementation.
Compatibility can be maintained either by tailoring the header to the compiler, or by writing the header so that it adapts to the characteristics of the compiler.
As a programmer, you don't have to worry about how correctness is maintained (though of course there's nothing wrong with being curious). You can rely on it being done correctly -- or you can complain to the provider about a serious bug.

Each C or C++ implementation that defines uint32_t defines it in a way that works for that implementation. It may use typedef unsigned int uint32_t; only if unsigned int is satisfactory for uint32_t in that implementation.
The fact that typedef unsigned int uint32_t; appears in <stdint.h> in one C or C++ implementation does not mean it will appear in <stdint.h> for any other C or C++ implementation. An implementation in which unsigned int were not suitable for uint32_t would have to provide a different <stdint.h>. <stdint.h> is part of the implementation and changes when the implementation changes.

uint32_t guarantee 32 bits?
Yes.
If CHAR_BIT == 16, uint32_t would be 2 "bytes". A "byte" is not always 8 bits in C.
The size of int is not a major issue concerning the implementation uintN_t.
uintN_t (N = 8,16,32,64) are optional non-padded types that independently exist when and if the system can support them. It is extremely common to find them implemented, especially the larger ones.
intN_t is similarly optional and must be 2's complement.

Related

Is there an actual 8-bit integer data type in C++

In c++, specifically the cstdint header file, there are types for 8-bit integers which turn out to be of the char data type with a typedef. Could anyone suggest an actual 8-bit integer type?
Yes, you are right. int8_t and uint8_t are typedef to char on platforms where 1 byte is 8 bits. On platforms where it is not, appropriate definition will be given.
Following answer is based on assumption that char is 8 bits
char holds 1 byte, which may be signed or unsigned based on implementation.
So int8_t is signed char and uint8_t is unsigned char, but this will be safe to use int8_t/uint8_t as actual 8-bit integer without relying too much on the implementation.
For a implementer's point of view, typedeffing where char is 8 bits makes sense.
Having seen all this, It is safe to use int8_t or uint8_t as real 8 bit integer.

is it possible to get definitive/absolute sized types in C/C++?

I've glossed over some documentation and it seems like the spec only requires 'int' or 'long' or whatever to be able to hold "at least some range of values" (often corresponding to the max range afforded by n bytes).
Anyways, is there a reasonable way to ask for an integer of exactly n bits/bytes? I don't even need a way to specify arbitrary length or anything weird, I'd just want a type with definitively 2 bytes, or definitively 4 bytes. like "int32" or something.
Currently, the way I'm dealing with this is by having a char array of n length, then casting it to an int * and dereferencing.
(My reasoning for wanting this has to do with reading/writing to files directly from structs- and I acknowledge that with this I'll have to worry about struct packing and endianness and stuff with that, but that's another issue...)
Also, "compatibility" with like super limited embedded systems is not a particular concern.
Thanks!
The c++11 standard defines integer types of definite size, provided they are available on the target architecture.
#include <cstdint>
std::int8_t c; // 8-bit unsigned integer
std::int16_t s; // 16-bit unsigned integer
std::int32_t i; // 32-bit unsigned integer
std::int64_t l; // 64-bit unsigned integer
and the corresponding unsigned types with
std::uint8_t uc; // 8-bit unsigned integer
std::uint16_t us; // 16-bit unsigned integer
std::uint32_t ui; // 32-bit unsigned integer
std::uint64_t ul; // 64-bit unsigned integer
As noted in the comments, these types are also available in C from the stdint.h header without the std:: namespace prefix:
#include <stdint.h>
uint32_t ui;
In addition to the types of definite size, these header files also define types
that are at least n bits wide but may be larger, e.g. int_least16_t with at least 16 bits
that provide the fastest implementation of integers with at least n bits but may be larger, e.g. std::int_fast32_t with at least 32 bits.
The typed declared in <cstdint>, such as int32_t will either be exactly that number of bits [32 in this example], or not exist if the architecture doesn't support that size values. There are also types int_fast32_t which is guaranteed to hold a 32-bit value, but could be larger, and int_fast32_t which has a similar guarantee.
The current c++ standard provides Fixed width integer types like std::int16_t std::uint16_t, where 16 means the type size in bits.
You can use the types from <stdint.h>, but you cannot be sure that there is exactly the type you want.
If your architecture does have exact 32 bit types, which is highly likely, then you can use int16_t, uint16_t, int32_t and uint32_t, if not, the types int_fast32_t and uint_fast32_t as well as int_least32_t and uint_least32_t , etc. are always available.

Compiler Independent Types

I've seen several libraries and some C++ header files that provide compiler independent types but I don't understand quite why they are compiler independent.
For example:
int Number; // Not compiler Independent
typedef unsigned int U32;
U32 Number2; // Now this is compiler independent
Is this above true? If so, why? I don't quite understand why the usage of a typedef would mean that the size of Number2 is the same across compilers.
Elaborating on the comment,
Proposition : Use a typedef for compiler independence.
Rationale : Platform independence is a Good Thing
Implementation:
#ifdef _MSC_VER
#if _MSC_VER < 1400
typedef int bar;
#elif _MSC_VER < 1600
typedef char bar;
#else
typedef bool bar;
#else
#error "Unknown compiler"
#endif
The preprocessor macro chain is the important part not the typedef.
Disclaimer: I haven't compiled it!
I'm assuming that you meant for the types to be the same with unsigned int Number.
But no, these are exactly the same. Both declarations, Number and Number2, have the same type. Neither is more compiler independent than the other.
However, the point of using a typedef like this is so that the developers of the library can easily change the integer type used by all functions that use U32. If, for example, they are on a system that where an unsigned int is not 32 bits, but an unsigned long is, they could change the typedef to:
typedef unsigned long U32;
In fact, it's possible to use the build system to conditionally change the typedef depending on the target platform.
However, if you want a nice standardised way to ensure that the type is a 32 bit unsigned integer type, I recommend using std::uint32_t from the <cstdint> header. However, this type is not guaranteed to exist if you're on a machine with no 32 bit integer type. Instead, you can use std::uint_least32_t, which will give you the smallest integer type with at least 32 bits.
As stated in the comments, the shown typedef is not compiler independent.
If you want a compiler independent way to get fixed sizes, you might want to use cstdint.
This header file actually comes with your compiler and assures you a minimum size, but no maximum for bigger types (64 bit, 128 bit).
If you want to be completely sure about all the sizes of your types, you need to check it.

Difference between different integer types

I was wondering what is the difference between uint32_t and uint32, and when I looked in the header files it had this:
types.h:
/** #brief 32-bit unsigned integer. */
typedef unsigned int uint32;
stdint.h:
typedef unsigned uint32_t;
This only leads to more questions:
What is the difference between
unsigned varName;
and
unsigned int varName;
?
I am using MinGW.
unsigned and unsigned int are synonymous, much like unsigned short [int] and unsigned long [int].
uint32_t is a type that's (optionally) defined by the C standard. uint32 is just a name you made up, although it happens to be defined as the same thing.
There is no difference.
unsigned int = uint32 = uint32_t = unsigned in your case and unsigned int = unsigned always
unsigned and unsigned int are synonymous for historical reasons; they both mean "unsigned integer of the most natural size for the CPU architecture/platform", which is often (but by no means always) 32 bits on modern platforms.
<stdint.h> is a standard header in C99 that is supposed to give type definitions for integers of particular sizes, with the uint32_t naming convention.
The <types.h> that you're looking at appears to be non-standard and presumably belongs to some framework your project is using. Its uint32 typedef is compatible with uint32_t. Whether you should use one or the other in your code is a question for your manager.
There is absolutely no difference between unsigned and unsigned int.
Whether that type is a good match for uint32_t is implementation-dependant though; an int could be "shorter" than 32 bits.

How can I get bitfields to arrange my bits in the right order?

To begin with, the application in question is always going to be on the same processor, and the compiler is always gcc, so I'm not concerned about bitfields not being portable.
gcc lays out bitfields such that the first listed field corresponds to least significant bit of a byte. So the following structure, with a=0, b=1, c=1, d=1, you get a byte of value e0.
struct Bits {
unsigned int a:5;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
} __attribute__((__packed__));
(Actually, this is C++, so I'm talking about g++.)
Now let's say I'd like a to be a six bit integer.
Now, I can see why this won't work, but I coded the following structure:
struct Bits2 {
unsigned int a:6;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
} __attribute__((__packed__));
Setting b, c, and d to 1, and a to 0 results in the following two bytes:
c0 01
This isn't what I wanted. I was hoping to see this:
e0 00
Is there any way to specify a structure that has three bits in the most significant bits of the first byte and six bits spanning the five least significant bits of the first byte and the most significant bit of the second?
Please be aware that I have no control over where these bits are supposed to be laid out: it's a layout of bits that are defined by someone else's interface.
(Note that all of this is gcc-specific commentary - I'm well aware that the layout of bitfields is implementation-defined).
Not on a little-endian machine: The problem is that on a little-endian machine, the most significant bit of the second byte isn't considered "adjacent" to the least significant bits of the first byte.
You can, however, combine the bitfields with the ntohs() function:
union u_Bits2{
struct Bits2 {
uint16_t _padding:7;
uint16_t a:6;
uint16_t b:1;
uint16_t c:1;
uint16_t d:1;
} bits __attribute__((__packed__));
uint16_t word;
}
union u_Bits2 flags;
flags.word = ntohs(flag_bytes_from_network);
However, I strongly recommend you avoid bitfields and instead use shifting and masks.
Usually you can't do strong assumptions on how the union will be packed, every compiler implementation may choose to pack it differently (to save space or align bitfields inside bytes).
I would suggest you to just work out with masking and bitwise operators..
from this link:
The main use of bitfields is either to allow tight packing of data or to be able to specify the fields within some externally produced data files. C gives no guarantee of the ordering of fields within machine words, so if you do use them for the latter reason, you program will not only be non-portable, it will be compiler-dependent too. The Standard says that fields are packed into ‘storage units’, which are typically machine words. The packing order, and whether or not a bitfield may cross a storage unit boundary, are implementation defined. To force alignment to a storage unit boundary, a zero width field is used before the one that you want to have aligned.
C/C++ has no means of specifying the bit by bit memory layout of structs, so you will need to do manual bit shifting and masking on 8 or 16bit (unsigned) integers (uint8_t, uint16_t from <stdint.h> or <cstdint>).
Of the good dozen of programming languages I know, only very few allow you to specify bit-by-bit memory layout for bit fields: Ada, Erlang, VHDL (and Verilog).
(Community wiki if you want to add more languages to that list.)