c++strtolstrtoull

stroll, strol functions not giving correct output for long_min


For the following code

#include <bits/stdc++.h>
using namespace std;
int main()
{
   bitset<64>b(numeric_limits<long>::min());
   string s=b.to_string();
   char *ptr=new char [s.size()+1];
   strcpy(ptr,s.c_str());
   long l1=strtol(ptr,NULL,2);
   cout<<"l1= "<<l1<<endl;
  long l2=strtoul(ptr,NULL,2);
   cout<<"l2= "<<l2<<endl;
   cout<<strtoul(ptr,NULL,2)<<endl;
}

The output is

l1= 9223372036854775807
l2= -9223372036854775808
9223372036854775808

Why is l1 not long_min and why is l2? I've read that the string can contain +/- sign in the beginning for ato*,strto* functions. But negative numbers in binary don't have any - sign in 2's complement that computer uses. I'm confused.


Solution

  • The unsigned long int value

    9223372036854775808
    

    outputted by this statement

    cout<<strtoul(ptr,NULL,2)<<endl;
    

    can not be represented in an object of the type signed long int.

    In this statement

    long l1=strtol(ptr,NULL,2);
    

    as the value is not representable in the type signed long int the function strtol returns LONG_MAX (because there is no minus sign in the string). And this value is outputted by this statement

    cout<<"l1= "<<l1<<endl;
    

    From the C Standard (7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions)

    8 The strtol, strtoll, strtoul, and strtoull functions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any), and the value of the macro ERANGE is stored in errno.

    However the value is representable as an unsigned long int. So this call of the function strtoul returns the correct value

    long l2=strtoul(ptr,NULL,2);
    

    but the value is assigned to an object of the type signed long int. So its most significant bit is interpreted as the sign bit and the next statement

    cout<<"l2= "<<l2<<endl;
    

    outputs the value LONG_MIN.