0

I'm trying to convert a pointer to string, and the string back to the pointer (lexical casting) using the following code. The conversion from pointer to string works fine, but not the other way round.

Why does this happen? Is there some other way I can convert a string to a pointer?

I'm not worried about errors caused by incorrect format of the string. The string I'm trying to convert to a pointer will always be generated by converting a pointer to string.

Here's the code:

//TB_ConvertToString.cpp

#include<iostream>
#include<cstdio>
#include<sstream>
#include<string>

//Functions to convert data types to and from strings   
template <typename T> std::string ToString ( T Number )
{
    std::stringstream ss;
    ss << Number;
    return ss.str();
};

template <typename T> 
T FromString ( const std::string &Text )
{
    std::stringstream ss(Text);
    T result;
    ss >> result;
    return result;
}
//-------------------------------------------------


using namespace std;

int main()
{
    int a =10;  
    int* p1 = &a;
    // this works------------
    string s1 = ToString<int *>(p1);
    printf("\n ptr: %s",s1.c_str());
    //----------------------

    //this gives compilation errors -----
    //int * p2 = FromString<int *>(s1);
    //printf("\n ptr: %p",p2);
    //----------------------


    cout<<"\n\n";
    return 0;
};

Un-commenting the problem section gives the following compilation errors:

nehak@Marvin:~/Desktop$ g++ TB_ConvertToString.cpp 
TB_ConvertToString.cpp: In function ‘T FromString(const string&) [with T = int*, std::string = std::basic_string<char>]’:
TB_ConvertToString.cpp:39:33:   instantiated from here
TB_ConvertToString.cpp:21:2: error: no match for ‘operator>>’ in ‘ss >> result’
TB_ConvertToString.cpp:21:2: note: candidates are:
/usr/include/c++/4.6/istream:122:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__istream_type& (*)(std::basic_istream<_CharT, _Traits>::__istream_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:122:7: note:   no known conversion for argument 1 from ‘int*’ to ‘std::basic_istream<char>::__istream_type& (*)(std::basic_istream<char>::__istream_type&) {aka std::basic_istream<char>& (*)(std::basic_istream<char>&)}’
/usr/include/c++/4.6/istream:126:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__ios_type& (*)(std::basic_istream<_CharT, _Traits>::__ios_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>, std::basic_istream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
/usr/include/c++/4.6/istream:126:7: note:   no known conversion for argument 1 from ‘int*’ to ‘std::basic_istream<char>::__ios_type& (*)(std::basic_istream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}’
/usr/include/c++/4.6/istream:133:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:133:7: note:   no known conversion for argument 1 from ‘int*’ to ‘std::ios_base& (*)(std::ios_base&)’
/usr/include/c++/4.6/istream:169:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(bool&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:169:7: note:   no known conversion for argument 1 from ‘int*’ to ‘bool&’
/usr/include/c++/4.6/istream:173:7: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(short int&) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.6/istream:173:7: note:   no known conversion for argument 1 from ‘int*’ to ‘short int&’
/usr/include/c++/4.6/istream:176:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(short unsigned int&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:176:7: note:   no known conversion for argument 1 from ‘int*’ to ‘short unsigned int&’
/usr/include/c++/4.6/istream:180:7: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(int&) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.6/istream:180:7: note:   no known conversion for argument 1 from ‘int*’ to ‘int&’
/usr/include/c++/4.6/istream:183:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(unsigned int&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:183:7: note:   no known conversion for argument 1 from ‘int*’ to ‘unsigned int&’
/usr/include/c++/4.6/istream:187:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(long int&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:187:7: note:   no known conversion for argument 1 from ‘int*’ to ‘long int&’
/usr/include/c++/4.6/istream:191:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(long unsigned int&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:191:7: note:   no known conversion for argument 1 from ‘int*’ to ‘long unsigned int&’
/usr/include/c++/4.6/istream:196:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(long long int&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:196:7: note:   no known conversion for argument 1 from ‘int*’ to ‘long long int&’
/usr/include/c++/4.6/istream:200:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(long long unsigned int&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:200:7: note:   no known conversion for argument 1 from ‘int*’ to ‘long long unsigned int&’
/usr/include/c++/4.6/istream:205:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(float&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:205:7: note:   no known conversion for argument 1 from ‘int*’ to ‘float&’
/usr/include/c++/4.6/istream:209:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(double&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:209:7: note:   no known conversion for argument 1 from ‘int*’ to ‘double&’
/usr/include/c++/4.6/istream:213:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(long double&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:213:7: note:   no known conversion for argument 1 from ‘int*’ to ‘long double&’
/usr/include/c++/4.6/istream:217:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(void*&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>]
/usr/include/c++/4.6/istream:217:7: note:   no known conversion for argument 1 from ‘int*’ to ‘void*&’
/usr/include/c++/4.6/istream:241:7: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
/usr/include/c++/4.6/istream:241:7: note:   no known conversion for argument 1 from ‘int*’ to ‘std::basic_istream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}’
/usr/include/c++/4.6/bits/basic_string.tcc:998:5: note: template<class _CharT, class _Traits, class _Alloc> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, std::basic_string<_CharT, _Traits, _Alloc>&)
/usr/include/c++/4.6/bits/istream.tcc:957:5: note: template<class _CharT2, class _Traits2> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, _CharT2*)
/usr/include/c++/4.6/bits/istream.tcc:925:5: note: template<class _CharT, class _Traits> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, _CharT&)
/usr/include/c++/4.6/istream:709:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, unsigned char&)
/usr/include/c++/4.6/istream:714:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, signed char&)
/usr/include/c++/4.6/istream:756:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, unsigned char*)
/usr/include/c++/4.6/istream:761:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, signed char*)
nehak@Marvin:~/Desktop$ 
LihO
  • 41,190
  • 11
  • 99
  • 167
Neha Karanjkar
  • 3,390
  • 2
  • 29
  • 48
  • 3
    Define `"doesn't work"` – Peter Wood Mar 18 '13 at 09:52
  • Does this compiler **error** help at all: "Invalid operands to binary expression ('std::stringstream' (aka 'basic_stringstream') and 'int \*')" In other words, there is no overloaded extraction operator that takes an lhs-istream and a rhs-intptr. Just be glad you didn't pass a char* or you'd be fighting with segfaults rather than compiler errors. – WhozCraig Mar 18 '13 at 09:56
  • 1
    Why do you expect it to work? You are attempting to stream the contents of an `std::stringstream` into a pointer. – juanchopanza Mar 18 '13 at 09:56
  • There is a `<<` operator for inserting pointers to streams, but no `>>` operator for extracting them back. – n. m. could be an AI Mar 18 '13 at 09:58
  • @juanchopanza , Your comment does not explain why it shouldn't work. It works for all other built-in types like int, float etc - just not pointers. The Questions asks if there's any other way to do the conversion, if the current does not work. – Neha Karanjkar Mar 18 '13 at 10:00
  • Why do you need to do this? For the pointer to make sense you must still be inside the same process on the same physical machine (unless you have some kind of fixed linking/addressing going on), and if that is the case then why do you need to store the pointer in an intermediate string? I can see why you might want to convert from pointer to string (for a human to read), but can't think why you'd EVER go back the other way. – Wayne Uroda Mar 18 '13 at 10:02

4 Answers4

4

Your problem could be actually narrowed down to this simple test case:

std::stringstream ss("0xbf845748");
int* p2;
ss >> p2;

which doesn't work, because there is no such overload of >> operator that would initialize your pointer. To make this extraction of pointer work, you could use void* or you could even extract the integral number, that is big enough to hold this address and then use reinterpret_cast<T> to make your pointer point to this address, just be really careful not to end up with char* overload because that might cause you much worse problems that you are dealing with now.

Just note that trying to initialize a pointer by using the address stored in std::string is really bad idea. Before you decide to make it work, make sure it is really what you want here. There are most likely much more reasonable ways how to avoid this.

LihO
  • 41,190
  • 11
  • 99
  • 167
  • 1
    Even if this is done, the OP is still beholden to the write-format of a pointer on the output stream. There is no guarantee that write-format will match a consistent read-format into something like a `uintptr_t` even with hex turned on. Furthermore, this whole thing falls apart without a `void*`-cast on the original pointer-write, since there *is* a defined writer for `char*`. I.e. if `char*` is ever the template type the OP has a whole new set of problems to worry about. – WhozCraig Mar 18 '13 at 10:05
  • @WhozCraig: Indeed. Initializing a pointer by using the address stored in `std::string` doesn't seem to be right thing to do at all. – LihO Mar 18 '13 at 10:09
  • 1
    yeah, its a terrible idea. if he really wanted it to work (that being a real stretch) he could cast to (uintptr_t), *then* do the write, and the opposite on the read. But then an SFINAE issue pops up and a special version for `std::is_pointer` would likely be required. All in all just an outright bad idea, I agree. – WhozCraig Mar 18 '13 at 10:12
2

The problem is that any type of pointer can be implicit cast to void*, but void* can not be cast to any type of pointer. In your case you should specialize FromString function for all pointers. Like this

template <typename T> 
T FromString ( const std::string &Text,
    std::enable_if< ! std::is_pointer< T >::value >::type * = nullptr )
{
    std::stringstream ss(Text);
    T result;
    ss >> result;
    return result;
}

template <typename T> 
T FromString ( const std::string &Text,
    std::enable_if< std::is_pointer< T >::value >::type * = nullptr )
{
    std::stringstream ss(Text);
    void * result;
    ss >> result;
    return (T)result;
}
borisbn
  • 4,988
  • 25
  • 42
2

@LihO, thanks! That works. I had to use std::hex while extracting the pointer though.

    string s1 = "0x7fff3e8aee1c";
    stringstream ss;
    ss<<s1;
    long long unsigned int i;
    ss>>std::hex>>i;
    int * i_ptr=reinterpret_cast<int *>(i);
Neha Karanjkar
  • 3,390
  • 2
  • 29
  • 48
1

I ended up using std::stoul.

void *p = std::stoul(str.c_str(), 0, 16);
FernandoZ
  • 439
  • 6
  • 13