0

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.

duplex143
  • 454
  • 4
  • 19
  • 1
    errno is supposed to be set to ERANGE, don't forget to check it. [And this](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h). – Hans Passant Apr 14 '20 at 10:14

2 Answers2

1

You get an ERANGE error for supplying a positive value larger than what a long can hold. To make it work with strtol you need to add a -:

#include <bitset>
#include <cstring>
#include <iostream>
#include <limits>
#include <string>

int main()
{
   std::bitset<64> b(std::numeric_limits<long>::min());

   std::string s = "-" + b.to_string();

   long l1=strtol(s.c_str(), NULL, 2);
   std::cout << "l1= " << l1 << '\n';
}

Possible output:

l1= -9223372036854775808
Ted Lyngmo
  • 37,764
  • 5
  • 23
  • 50
  • ptr in my example is `LONG_MIN` which a long can hold. Why is the sign necessary for base 2? Have I supplied `LONG_MAX+1` or `LONG_MIN` to strtol? – duplex143 Apr 14 '20 at 10:46
  • 1
    `strtol` requires a `-` for negative values, otherwise it'll be interpreted as a positive value. The base doesn't matter. – Ted Lyngmo Apr 14 '20 at 10:54
1

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.

Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268