Home » C++ » How do I ask for “at least” a size of an int in C

How do I ask for “at least” a size of an int in C

Posted by: admin November 30, 2017 Leave a comment

Questions:

The situation:

I have an application written in C which is resource intensive, and designed to be portable. I want to allow the compiler to select the fastest int size for the architecture, provided it is at least 32 bits.

Is it possible to select a size of “at least” 32 bits, or will the compiler optimize these kinds of things form me automatically?

Answers:

The standard header stdint.h provides the types int_leastN_t and uint_leastN_t, where N is 8, 16, 32, and 64 (and possibly others, but these are not required). These are standard as of C99.

It also provides “fast” alternatives, aka int_fastN_t and uint_fastN_t, with the same values of N.

So, in your case, you can use int_least32_t or int_fast32_t.

Questions:
Answers:

As others have noted, the standard include files define int_fast32_t, int_least32_t, uint_fast32_t, uint_least32_t which should likely behave as you want, but such types need to be used with extreme care. Because of integer promotion rules, there is no way for C code to avoid using types int and unsigned int. Further, integer literals may not always be of the types one expects. A comparison between an int_fast32_T and the literals 0xABCD1234 or 12345u, for example, may be performed as either signed or unsigned, depending upon whether int is 16, 32, or 64 bits. Likewise, if n is 32 bits or larger, the meaning of n &= ~0x8000; would be different on a 16-bit machine from on a larger one.

The C standard was never particularly designed to facilitate writing code which cares about integer sizes, but will nonetheless work compatibly on hardware with different sizes. Types like int_fast32_t make it easy to write code which seems like it should be portable, but may encourage complacency with respect to all of the nasty little traps hidden in the language.

Questions:
Answers:

This question was tagged as C++ too, so here is a solution for template metaprogramming lovers like me.

Requirements

  • A typelist type, named list here.
  • A Haskell-like filter metafunction.
  • A head metafunction to get the first element of a typelist.

The code

This solution automates the accepted solution (Which is just “go to stdint.h and select the most apropiate for you”). That job could be done by the compiler, couldn’t it?

First list all the platform specific fastest integer types declared at <cstdint>:

using integer_types = list<std::int_fast8_t,std::int_fast16_t,
                           std::int_fast32_t,std::int_fast64_t>;

Note the list is sorted by increasing integer size.
Now define a filtering predicate. In our case, the size should be less than the size specified by the user (name it SIZE):

template<typename T>
using f = std::integral_constant<bool,sizeof(T)*CHAR_BITS <= SIZE>;

And then filter the list of integer types and get the first element of the result:

using best_integer_t = head<filter<f,integer_types>>;

Summarized solution

template<std::size_t SIZE>
struct fastest_integer_impl
{
    //Guard for the case the user specified less than one byte size:
    static constexpr const std::size_t size = SIZE >= CHAR_BITS ? size : CHAR_BITS;

    using integer_types = list<std::int_fast8_t,std::int_fast16_t,
                               std::int_fast32_t,std::int_fast64_t>;

    template<typename T>
    using f = std::integral_constant<bool,sizeof(T)*CHAR_BITS <= size>;

    using type = head<filter<f,integer_types>>;
};

template<std::size_t SIZE>
using fastest_integer = typename fastest_integer_impl<SIZE>::type;

Questions:
Answers:

fastest => align to architecture using pragma pack. Without this, in case the memory is not aligned, it would require more than one memory access.

min 32 => use int specifier – enough. This ensures 32 bits in linux across all architectures to my knowledge.