[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Help needed with gcc-7 error



On 08/28/2017 10:54 PM, Martin Eberhard Schauer wrote:
>>>  Well, casting to long helped - but in how far does making
> 
>>>  abs(unsigned - unsigned)
> 
>>>  no sense?  This does not sound very logical to me.
> 
>> The result of (unsigned - unsigned) is unsigned.
> What about A, B both unsigned and B > A?

This will wrap around. Current C/C++ standards define that unsigned
types with N bits always operate mod 2^N. Whereas on the other hand
any overflow / underflow with signed types is undefined behavior.

Note however that this rule only holds true for int or larger. For
smaller types (unsigned short, unsigned char) these are promoted to
int (because it fits in int) when you subtract them.

For example:

#include <cstdlib>
#include <iostream>

int main()
{
  unsigned char a = 23, b = 42;
  std::cout << std::abs(a - b) << std::endl;
  return 0;
}

would compile and print out 19 when run, because a - b is promoted
to int and std::abs(int) does exist.

The problem is that std::abs(unsigned) doesn't and unsigned can be
converted to both int (narrowing conversion) or long (widening
conversion), and since both are legal, the compiler doesn't know
which overload to take.

Regards,
Christian

PS: In order to illustrate how integer promotion works in practice,
you can try the following program:

#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <cstdlib>

template<typename IntType>
void printType(char const* typeName)
{
  std::cout << std::setw(18) << typeName << ": typeid().name() == \"" << typeid(IntType).name() << "\", sizeof() == " << sizeof(IntType) << "\n";
}

#define PRINT_TYPE(typeName) printType<typeName>(#typeName)

template<typename IntTypeA, typename IntTypeB>
void doTest(char const* typeNameA, char const* typeNameB)
{
  IntTypeA a = 1;
  IntTypeB b = 2;
  std::cout << std::setw(18) << typeNameA << " - " << std::setw(18) << typeNameB << ": typeid(a - b).name() = \"" << typeid(a - b).name() << "\", a - b = " << (a - b) << '\n';
}

#define DO_TEST(typeNameA, typeNameB) doTest<typeNameA, typeNameB>(#typeNameA, #typeNameB)

#define TEST_HELPER(typeNameA) \
    DO_TEST(typeNameA, char); \
    DO_TEST(typeNameA, signed char); \
    DO_TEST(typeNameA, unsigned char); \
    DO_TEST(typeNameA, signed short); \
    DO_TEST(typeNameA, unsigned short); \
    DO_TEST(typeNameA, signed int); \
    DO_TEST(typeNameA, unsigned int); \
    DO_TEST(typeNameA, signed long); \
    DO_TEST(typeNameA, unsigned long); \
    DO_TEST(typeNameA, signed long long); \
    DO_TEST(typeNameA, unsigned long long);

int main()
{
    PRINT_TYPE(char);
    PRINT_TYPE(signed char);
    PRINT_TYPE(unsigned char);
    PRINT_TYPE(signed short);
    PRINT_TYPE(unsigned short);
    PRINT_TYPE(signed int);
    PRINT_TYPE(unsigned int);
    PRINT_TYPE(signed long);
    PRINT_TYPE(unsigned long);
    PRINT_TYPE(signed long long);
    PRINT_TYPE(unsigned long long);

    TEST_HELPER(char);
    TEST_HELPER(signed char);
    TEST_HELPER(unsigned char);
    TEST_HELPER(signed short);
    TEST_HELPER(unsigned short);
    TEST_HELPER(signed int);
    TEST_HELPER(unsigned int);
    TEST_HELPER(signed long);
    TEST_HELPER(unsigned long);
    TEST_HELPER(signed long long);
    TEST_HELPER(unsigned long long);


    return 0;
}


Reply to: