Search code examples
c++macosgccambiguous

Why is there ambiguity between uint32_t and uint64_t when using size_t on Mac OS X?


Consider following example code:

#include <iostream>
#include <inttypes.h>

using namespace std;

int f(uint32_t i)
{
  return 1;
}
int f(uint64_t i)
{
  return 2;
}

int main ()
{
  cout << sizeof(long unsigned) << '\n';
  cout << sizeof(size_t) << '\n';
  cout << sizeof(uint32_t) << '\n';
  cout << sizeof(uint64_t) << '\n';
  //long unsigned x = 3;
  size_t x = 3;
  cout << f(x) << '\n';
  return 0;
}

This fails on Mac OSX with:

$ g++ --version
i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
$ make test
g++     test.cc   -o test
test.cc: In function 'int main()':
test.cc:23: error: call of overloaded 'f(size_t&)' is ambiguous
test.cc:6: note: candidates are: int f(uint32_t)
test.cc:10: note:                 int f(uint64_t)
make: *** [test] Error 1

Why? Because 'size_t' should be unsigned and either 32 bit or 64 bit wide. Where is the ambiguity then?

Trying the same with 'unsigned long x' instead of 'size_t x' results in an analogous ambiguity error message.

On Linux/Solaris systems, testing with different GCC versions, different architectures etc. there is no ambiguity reported (and the right overload is used on each architecture).

Is this a Mac OS X bug or a feature?


Solution

  • Under Mac OS, those types are defined as:

    typedef unsigned int         uint32_t;
    typedef unsigned long long   uint64_t;
    

    Where as size_t is defined as __SIZE_TYPE__:

    #if defined(__GNUC__) && defined(__SIZE_TYPE__)
    typedef __SIZE_TYPE__       __darwin_size_t;    /* sizeof() */
    #else
    typedef unsigned long       __darwin_size_t;    /* sizeof() */
    #endif
    

    So if you change your code to:

    #include <iostream>
    #include <inttypes.h>
    
    using namespace std;
    
    int f(uint32_t i)
    {
      return 1;
    }
    int f(uint64_t i)
    {
      return 2;
    }
    
    int f (unsigned long i)
    {
      return 3;
    }
    
    int main ()
    {
      cout << sizeof(unsigned long) << '\n';
      cout << sizeof(size_t) << '\n';
      cout << sizeof(uint32_t) << '\n';
      cout << sizeof(uint64_t) << '\n';
      //long unsigned x = 3;
      size_t x = 3;
      cout << f(x) << '\n';
      return 0;
    }
    

    And run it, you will get:

    $ g++ -o test test.cpp
    $ ./test
    8
    8
    4
    8
    3