Dominus
Dominus

Reputation: 93

How do I use an integer type of a specific size in C++?

I need integer types of specific widths in C++, but I am not sure what type to use: int, long, etc. I realize I could use sizeof to find the size of each different integer type, but int, long and long long are not platform independent. This task would also be way too tedious.

Is there any way to specifiy an integer type of a specific size (such as a 32-bit or 64-bit integer) in C++? How would I go about doing this?

Upvotes: 0

Views: 1129

Answers (3)

Ryan Zhang
Ryan Zhang

Reputation: 1935

I think what you're looking for is fixed width integer types. These are defined in the header <cstdint>.

For your purposes, you could stick with int[xx]_t, where you replace [xx] with the width of the integer type you need, in bits. uint[xx]_t does something similar, with unsigned integer types.

You could, for example, use int8_t, int16_t, uint8_t, uint_16t, etc.

Upvotes: 7

Mike Vine
Mike Vine

Reputation: 9852

If you need to work out the type at compile time from a constexpr number of bits you can do:

#include <type_traits>
#include <iostream>

template <int NumBits, typename=void>
struct uint_selector;

template <int NumBits>
struct uint_selector<NumBits, std::enable_if_t< 0 <= NumBits && NumBits <= 8>>
{
    typedef uint8_t int_type;
};

template <int NumBits>
struct uint_selector<NumBits, std::enable_if_t<8 < NumBits && NumBits <= 16 >>
{
    typedef uint16_t int_type;
};

template <int NumBits>
struct uint_selector<NumBits, std::enable_if_t<16 < NumBits && NumBits <= 32 >>
{
    typedef uint32_t int_type;
};

template <int NumBits>
struct uint_selector<NumBits, std::enable_if_t<32 < NumBits && NumBits <= 64 >>
{
    typedef uint64_t int_type;
};

// Then use as:
int main()
{
    // my_val will be the smallest standard type which is big enough type to hold 15 bits (e.g. a uint16_t)
    uint_selector<15>::int_type my_val = 5;
}

Upvotes: 3

Stephen Newell
Stephen Newell

Reputation: 7873

You can use template specialization of a type trait, provided you know the sizes at compile time.

#include <cstdint>
#include <type_traits>

template <std::size_t SIZE>
struct num_selector;

template<>
struct num_selector<sizeof(short)> {
    using type = short;
};

template<>
struct num_selector<sizeof(int)> {
    using type = int;
};

template <std::size_t SIZE>
using num_selector_t = typename num_selector<SIZE>::type;

int main() {
    std::uint8_t shortish[sizeof(short)];
    std::uint8_t intish[sizeof(int)];

    static_assert(std::is_same_v<num_selector_t<sizeof(shortish)>, short>);
    static_assert(std::is_same_v<num_selector_t<sizeof(intish)>, int>);
    return 0;
}

This make some assumptions that short and int are different sizes, but that's reasonable on most platforms (and can be checked via static_assert if you're concerned).

If you don't know how many bytes you're going to read until you're actually reading them (e.g., some end of field marker), you're better off picking the largest type you could ever need and just dealing with that.

Upvotes: 0

Related Questions