Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When int isn't an int (intX_t)

I have some headache inducing problems here.

Basically I'm trying to make a library compatible with different Arduino systems (not an Arduino question).

I have a situation where types no longer match, as in an int is no longer equivalent to its identical fixed width type. In the limited environment provided (no stdlib and such) I have written my own type trait classes for the features I need.

Everything works fine using GCC 4.8.1 (avr) & Extensa-1x106-GCC (ESP8266), but not in GCC 4.8.3 (SAM,SAMD cores).

Basically I have knuckled down my code to show the problem in this very basic code (int is confirmed to have 4 bytes on the failing 32-bit platform compilers):

template < typename T, typename U > struct is_same{ enum { value = false }; };
template < typename T > struct is_same< T, T >    { enum { value = true }; };

void setup() {
  static_assert( is_same<int,int32_t>::value, "Not integer");
}

void loop(){}

You can view a 'normal' C++ implementation here (above is a basic implementation for use within the Arduino IDE): http://cpp.sh/377e

By the way, the static assert does not fire in the cpp.sh compiler either.

Is 4.8.1 incorrect, meaning int and int32_t should be considered different types. Or is 4.8.3 incorrect and they should be equivalent if equally sized defined by the implementation.

I was using the code below to detect any type of integer, which was where I found my error originally.

template< typename T >
    struct is_integer{
        enum{
            V8    = is_same< T, uint8_t >::value  || is_same< T, int8_t >::value,
            V16   = is_same< T, uint16_t >::value || is_same< T, int16_t >::value,
            V32   = is_same< T, uint32_t >::value || is_same< T, int32_t >::value,
            V64   = is_same< T, uint64_t >::value || is_same< T, int64_t >::value,
            value = V8 || V16 || V32 || V64
        };
};

I of course can change it to check for char, int, long, etc.. but it will still require checking for all fixed width variations and most likely the int_fastX_t and int_leastX_t types, which seems like a super redundant method to ensure maximum usability.

Any ideas?

Cheers, I appreciate any input!

like image 997
Chris A Avatar asked Sep 28 '15 11:09

Chris A


2 Answers

This is governed by the C standard; the C++ one just inherits the behaviour by explicit reference.

What the C standard says is:

  • If int32_t is defined, it refers to a signed 32-bit 2's complement integer.

  • If the implementation provides a signed 32-bit 2's complement integer type, it must provide the typedef int32_t which will refer to it.

Nowhere does it say that this 32-bit 2's complement signed integer type must be int. Technically, even if int is a 32-bit 2's complement integer type, it is perfectly possible for the implementation to also provide a distinct 32-bit 2's complement signed integer type and define int32_t to refer to that other type.

I am afraid the only fully generic solution would be to list all the fundamental types, fixed-width types, minimum-width types, and fast minimum-width types.

For something less daunting, it should be possible to inspect the documentation of the toolchains you wish to support to find what types they provide and how they name them. If this set of "toolchains you wish to support" is unbounded, I don't think there's an easier way out.

like image 75
Angew is no longer proud of SO Avatar answered Oct 21 '22 03:10

Angew is no longer proud of SO


From the C11 standard 7.20.1.1(1)

The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two’s complement representation. Thus, int8_t denotes such a signed integer type with a width of exactly 8 bits.

So int32_t is a signed integer that is exactly 32 bits wide.

An int though is defined as sizeof(int) being greater than or equal to a char(C++14 3.9.1(2)) and that an signed int must be able to represent [-32767, 32767](C11 5.2.4.2.1). That range is actually 16 bits.

So an int may never be equivalent to a intN_t as an intN_t can be a implementation defined type separate from a standard type.

like image 44
NathanOliver Avatar answered Oct 21 '22 03:10

NathanOliver