3

I am trying to compile the following code:

#include <stdlib.h>
static
unsigned iSqr( unsigned i )
{
    unsigned res1 = 2;
    unsigned res2 = i/res1;
    while( abs( res1 - res2 ) > 1 )
        {
        res1 = (res1 + res2)/2;
        res2 = i/res1;
        }
    return res1 < res2 ? res1 : res2;
}

using g++ test.cc -o test.

However, g++ compiler fails with the following error:

test.cc: In function 'unsigned int iSqr(unsigned int)':                                         
test.cc:8:29: error: call of overloaded 'abs(unsigned int)' is ambiguous                        
     while( abs( res1 - res2 ) > 1 )            
                             ^                  
In file included from /usr/include/c++/6/cstdlib:75:0,                                          
                 from /usr/include/c++/6/stdlib.h:36,                                           
                 from test.cc:2:                
/usr/include/stdlib.h:735:12: note: candidate: int abs(int)                                     
 extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;                            
            ^~~         
In file included from /usr/include/c++/6/stdlib.h:36:0,                                         
                 from test.cc:2:                
/usr/include/c++/6/cstdlib:185:3: note: candidate: __int128 std::abs(__int128)                  
   abs(__GLIBCXX_TYPE_INT_N_0 __x) { return __x >= 0 ? __x : -__x; }                            
   ^~~                  
/usr/include/c++/6/cstdlib:180:3: note: candidate: long long int std::abs(long long int)        
   abs(long long __x) { return __builtin_llabs (__x); }                                         
   ^~~                  
/usr/include/c++/6/cstdlib:172:3: note: candidate: long int std::abs(long int)                  
   abs(long __i) { return __builtin_labs(__i); }                                                
   ^~~     

Why this error is happening and how to fix it?

g++ version is: gcc version 6.3.0

Luke 10X
  • 1,071
  • 2
  • 14
  • 30
  • 2
    Possible duplicate of [Ambiguous call to abs](https://stackoverflow.com/questions/30084577/ambiguous-call-to-abs) – Chen Li May 11 '18 at 23:45

3 Answers3

6

abs in <stdlib.h>(since c++11): http://www.cplusplus.com/reference/cstdlib/abs/

          int abs (          int n);
     long int abs (     long int n);
long long int abs (long long int n);

The call will be ambiguous if overload resolution cannot select a match to the call that is uniquely better than such undifferentiable functions.

You can cast the argument explicitly like:

static_cast<int>(res1 - res2)
Chen Li
  • 4,824
  • 3
  • 28
  • 55
5

You can just cast the result to a signed datatype for abs to know which one you're calling like this:

while( abs( int(res1 - res2) ) > 1 )

but rethink again of what you need to do here as the result of minus operation on unsigned is still unsigned, so if the result goes below 0 it will turn to be a great number (as a normal overflow), so I think the use of signed variables is the best way to solve the issue in the first place

int iSqr( unsigned i )
{
    int res1 = 2;
    int res2 = i/res1;
    while( abs(res1 - res2) > 1 )
    {
        res1 = (res1 + res2)/2;
        res2 = i/res1;
    }
    return res1 < res2 ? res1 : res2;
}
Khaled Mohamed
  • 406
  • 5
  • 10
  • Perhaps `while ( abs( long(res1 - res2) ) > 1 )` would be safer, as `res1 - res2` could result in something that is higher than max signed int? – Luke 10X May 12 '18 at 00:16
  • 1
    In C++ long is a 32-bit container just as int ranging from -2,147,483,648 to 2,147,483,647. But you're correct for sure, it's safer to use 'long long' to avoid overflowing as it's the 64-bit container. Also don't forget that it'll still overflow if res1 and res2 are unsigned if it goes below 0, as the result is put in a container as the operands of the operation. – Khaled Mohamed May 12 '18 at 00:20
  • Also in c++ it's recommended to use c++ style casts, ie `static_cast(res1 - res2)` over the c style. I still prefer just using `int`s everywhere here though. – ricco19 May 12 '18 at 00:22
  • long is not guarantee to be 32-bit – Chen Li May 12 '18 at 00:29
  • Actually in most environments it will be 32-bit so it's safer to use long long if what we need is a "certain" 64-bit container to avoid overflowing @陳力 – Khaled Mohamed May 12 '18 at 00:34
  • I believe `long` is required to be at least 32 bits? It's usually the same size as `int` though. Personally I always use [fixed width integers](http://en.cppreference.com/w/cpp/types/integer) if I require a specific capacity. – ricco19 May 12 '18 at 00:37
  • The language and its implementation are different things. So, you can say `in most environments it will be 32-bit `, but you **can't** say `In C++ long is a 32-bit ` – Chen Li May 12 '18 at 00:37
  • Is it implementation defined? If it's required by the standard then the implementation is non-compliant, and the size of no data types should be trusted. – ricco19 May 12 '18 at 00:42
4

Edit: <cstdlib> should handle the overloads (and should be preferred anyways), see the question here

Note that there are some logic errors here. First of all, what you are doing is probably not what you want. res1 - res2 is arithmetic between two unsigned types, and so the result is also going to be unsigned. If you go below 0, you wrap back to max int. abs() is pointless here, that value will never be negative because the type disallows it. Even with the header that compiles this code, the compiler will still warn about this.

I highly recommend you stick to signed integers when dealing with arithmetic to avoid these pitfalls, and if you really need the storage, use 64-bit integers.

So my real answer would be, switch unsigned to int

Also note: unsigned res2 = i / res1; res2 will be truncated towards 0 here, I'm not sure if that is what you want or not.

ricco19
  • 713
  • 5
  • 16