Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

atoi() equivalent for intptr_t/uintptr_t

Is there a function in C++ (C++11, if it makes a difference) that converts a string to a uintptr_t or intptr_t? I can always use atoll() and cast it afterward, but it'd be nice to get a function that does 32-bit for 32-bit machines and 64-bit for 64-bit machines.

char* c = "1234567";
uintptr_t ptr = atoptr(c); // a function that does this;
like image 489
atanamir Avatar asked Nov 02 '22 01:11

atanamir


1 Answers

This is an IMO surprising gap in C++. While stringstream does the job, it is quite a heavy tool for such a simple task. Instead, you can write an inline function that calls the correct variation of strtoul based on the type sizes. Since the compiler knows the correct size it will be smart enough to replace calls to the function with calls to strtoul or strtoull. I.e., something like the following:

    inline uintptr_t handleFromString(const char *c, int base = 16)
    {
         // See if this function catches all possibilities.
         // If it doesn't, the function would have to be amended
         // whenever you add a combination of architecture and
         // compiler that is not yet addressed.
         static_assert(sizeof(uintptr_t) == sizeof(unsigned long)
             || sizeof(uintptr_t) == sizeof(unsigned long long),
             "Please add string to handle conversion for this architecture.");

         // Now choose the correct function ...
         if (sizeof(uintptr_t) == sizeof(unsigned long)) {
             return strtoul(c, nullptr, base);
         }

         // All other options exhausted, sizeof(uintptr_t) == sizeof(unsigned long long))
         return strtoull(c, nullptr, base);
    }

This will be easy to update if you ever decide to change the type of the handle. If you like angle brackets, you can also do something equivalent with templates though I don't see how that could be clearer.

Lastly, you can also use sscanf with the %tx format, i.e.

inline uintptr_t handleFromString(const char *c)
{
   ptrdiff_t h;
   sscanf(c, "%tx", &h); // only hex supported, %td for decimal.
   return (uintptr_t)h;
}

Unfortunately, no compiler that I tried on the Compiler Explorer managed to optimize the code in a way that removes the call to sscanf.

like image 131
tobi_s Avatar answered Nov 11 '22 15:11

tobi_s