Convert function pointer to string and back again

P

polas

Afternoon everyone - I have a question about function pointers. I want
to convert a function pointer to a string (which I will use elsewhere
in the code) and I then want to reconvert this string back to a
function pointer and call it.

I am thinking I can probably do something like
char * thestring=malloc(sizeof(char) * 30));
sprintf(thestring,"%p\0",function pointer);

But how would I convert this string back into a function pointer -
especially in a way which is portable?
 
M

Morris Keesan

Afternoon everyone - I have a question about function pointers. I want
to convert a function pointer to a string (which I will use elsewhere
in the code) and I then want to reconvert this string back to a
function pointer and call it.

I am thinking I can probably do something like
char * thestring=malloc(sizeof(char) * 30));
sprintf(thestring,"%p\0",function pointer);

But how would I convert this string back into a function pointer -
especially in a way which is portable?

Unfortunately, the easy way to do this is not portable, because
pointers to functions are inherently incompatible with other pointers,
in standard C (and I've used at least one implementation where function
pointers were quite a bit larger than pointers to data).

If you want to limit yourself to implementations where function pointers
are represented in the same way as other pointers, you can use the %P
format specifier of scanf, which the C99 standard says,
"Matches an implementation-defined set of sequences, which should be the
same as the set of sequences that may be produced by the %p conversion of
the fprintf function."

But both %p and %P operate on pointers to void, so you would have to be
sure
that your implementation can do the conversion to and from (void *) without
loss of information. If doing it this way, the code would be something
like:

char *thestring = malloc(30);/* but there's no way of knowing
* whether 30 is large enough, except
* by trial and error on each platform.
* sizeof(char) is 1, by definition, so
* is redundant noise
*/
sprintf(thestring, "%p", (void *)functionptr);
/* putting \0 in format makes the string end with TWO null chars */

then later

void * void_star_fp;
int (*fp)(); /* or whatever you want your function pointer to look like
*/

sscanf(thestring, "%P", &void_star_fp);
fp = (int (*)())void_star_fp;

-----------
The above is an interesting exercise, showing how to encode a data pointer
into a string and reconstruct it, including the important point that the
argument corresponding to %P in a scanf format MUST BE a (void **), and
NOT a pointer to some other pointer type.
But the actual portable way to encode a function pointer into a string and
then reconstruct it would be to treat the pointer as an array of unsigned
char, and encode and decode it byte by byte, e.g.

typedef int (*Fptr)(); /* to avoid having to repeatedly type (int (*)()) */
/* [replace the int and the () with whatever matches your functions'
return value and parameters.
*/
#define HEX_DIGITS_PER_CHAR (CHAR_BIT + 3)/4)
#define STRING_SIZE (sizeof(Fptr) * HEX_DIGITS_PER_CHAR + 1)
char thestring[STRING_SIZE]; /* unless you really need malloc */
size_t i;
unsigned char *fptr = (unsigned char *)&my_function_pointer;

for (i = 0; i < sizeof (Fptr); ++i) {
sprintf(thestring + (i * HEX_DIGITS_PER_CHAR), "%0*hhx",
HEX_DIGITS_PER_CHAR, fptr + i);
}

and then reconstruct the pointer later by treating the target pointer
as an array of unsigned chars, and using sscanf to read the hex values
and place them in those unsigned chars.

Disclaimer: THe above code is totally untested, and probably contains
bugs.
I haven't put a lot of thought into it (e.g. I almost posted this with
"%hhx"
as the sprintf format specifier).
 
B

Barry Schwarz

Afternoon everyone - I have a question about function pointers. I want
to convert a function pointer to a string (which I will use elsewhere
in the code) and I then want to reconvert this string back to a
function pointer and call it.

I am thinking I can probably do something like
char * thestring=malloc(sizeof(char) * 30));

sizeof(char) is guaranteed to always be 1.
sprintf(thestring,"%p\0",function pointer);

You should cast the pointer argument to void*. However, there is no
guarantee that a function pointer can be converted to an object
pointer. It appears to work on most systems.
But how would I convert this string back into a function pointer -
especially in a way which is portable?

Since the string was produced with %p, sscanf with a %p should convert
the string back to a void*. Then you can convert that void pointer
back to a function pointer (with the same caveat).

The conversion from void* to string and back to void* is guaranteed to
be portable in both the C89 and C99 standards. Whether the string
will fit in 30 characters is implementation dependent. Whether the
conversion from function pointer to void* or the reverse does what you
need is also implementation dependent.
 
E

Eric Sosman

Richard said:
In
Afternoon everyone - I have a question about function pointers. I
want to convert a function pointer to a string (which I will use
elsewhere in the code) and I then want to reconvert this string back
to a function pointer and call it.
[...]

Is there something wrong (actually wrong, not just "ugly")
about treating the function pointer as an array of bytes and
stringizing the bytes?

Yes, we all understand that one function pointer might have
many different string representations when done this way, but
surely any of them could reconstitute the original value.
 
K

Keith Thompson

Eric Sosman said:
Richard said:
In
Afternoon everyone - I have a question about function pointers. I
want to convert a function pointer to a string (which I will use
elsewhere in the code) and I then want to reconvert this string back
to a function pointer and call it.
[...]

Is there something wrong (actually wrong, not just "ugly")
about treating the function pointer as an array of bytes and
stringizing the bytes?

Yes, we all understand that one function pointer might have
many different string representations when done this way, but
surely any of them could reconstitute the original value.

That should work; I can't think of any way a conforming implementation
could break it.

It does introduce the temptation to do unwarranted things with the
resulting string.
 
P

Paul N

Afternoon everyone - I have a question about function pointers. I want
to convert a function pointer to a string (which I will use elsewhere
in the code) and I then want to reconvert this string back to a
function pointer and call it.

Are you sure you need to do this? If you are sending the string to a
different part of the same program, why not simply pass a function
pointer? And if you are passing the value across a network or the
like, the address will probably be wrong at the other end anyway.

If you need a string (eg to display it, for some reason) you can still
store it as a function pointer as well.
 
M

Mara Guida

Eric said:
Is there something wrong (actually wrong, not just "ugly")
about treating the function pointer as an array of bytes and
stringizing the bytes?

Suppose your process saves the function pointer in a string and goes
about is business ...

Then something happens in another process (Outlook got a large
attachment and the AntiVirus gets stuck in the heuristic analysis)
that forces the OS to dump everything to disk while the mess is sorted
out.
When the situation is under control, the OS gets the halted processes
stuff from disk, but puts them in a different memory location updating
pointers or pages or whatever.

.... and you now restore the function pointer from the string and call
the function


No, I have no idea how an OS manages memory for processes -- objects
or code :)
 
K

Keith Thompson

Mara Guida said:
Suppose your process saves the function pointer in a string and goes
about is business ...

Then something happens in another process (Outlook got a large
attachment and the AntiVirus gets stuck in the heuristic analysis)
that forces the OS to dump everything to disk while the mess is sorted
out.
When the situation is under control, the OS gets the halted processes
stuff from disk, but puts them in a different memory location updating
pointers or pages or whatever.

... and you now restore the function pointer from the string and call
the function


No, I have no idea how an OS manages memory for processes -- objects
or code :)

That shouldn't be a problem. Dumping a running program to disk and
then restoring it should be transparent to the program; if it isn't,
that's a bug in the OS. Saving and restoring a properly stringized
function pointer is no more of a problem than saving and later
re-using a saved function pointer value.

You're probably thinking of the possibility that restoring the process
updates the values of pointer variables so they now stringize
differently, and values not stored in objects of pointer type won't be
updated properly. But a conforming C implementation can't do that.
If I use memcpy() to copy an object's representation to an
appropriately sized array of unsigned char, then later use mempcy()
again to copy it back, I get the same value.
 
B

Barry Schwarz

Suppose your process saves the function pointer in a string and goes
about is business ...

Then something happens in another process (Outlook got a large
attachment and the AntiVirus gets stuck in the heuristic analysis)
that forces the OS to dump everything to disk while the mess is sorted
out.
When the situation is under control, the OS gets the halted processes
stuff from disk, but puts them in a different memory location updating
pointers or pages or whatever.

... and you now restore the function pointer from the string and call
the function


No, I have no idea how an OS manages memory for processes -- objects
or code :)

If this could be a problem, it would be a problem even if a pointer
had not been converted to a string. If pointer foo points to function
(or object) bar and the OS reloads bar to a different address, the
next time foo is dereferenced it will not find bar.

One of the benefits of the virtual storage model is that while an
object may be moved around in physical memory, its virtual (or
logical) address remains unchanged. The hardware and OS work
together to insure that any reference to the logical address is
translated to the correct current physical address.
 
A

Amandil

Richard said:
In
polas wrote:
Afternoon everyone - I have a question about function pointers. I
want to convert a function pointer to a string (which I will use
elsewhere in the code) and I then want to reconvert this string back
to a function pointer and call it.
[...]

     Is there something wrong (actually wrong, not just "ugly")
about treating the function pointer as an array of bytes and
stringizing the bytes?

     Yes, we all understand that one function pointer might have
many different string representations when done this way, but
surely any of them could reconstitute the original value.

How would that work? Assuming (for simplicity) that function pointers
have the same representation as data pointers, and are 4 bytes in size
(as on an x86). I understand the OP to be asking how to convert an
address 0x23456789 to (effectively) an array of chars:
{'0','x','2','3','4','5','6','7','8','9','\0'}.

What you are suggesting (and what Pete's example seems to show) would
be an array of chars (little-endian): {89, 67, 45, 23, 0}, or {'‰',
'g', 'E','#', '\0'} (obviously, character 0x89 will show up
differently on different systems).

I didn't try it out, so I may be wrong, and just not getting it.

Also, I'm curious, why the OP chose a length of 30 for his character
string. I'm sure it's ID, but it's nice to learn about different
implementations.

-- Marty Amandil
 
M

Morris Keesan

Richard said:
In
polas wrote:
Afternoon everyone - I have a question about function pointers. I
want to convert a function pointer to a string (which I will use
elsewhere in the code) and I then want to reconvert this string back
to a function pointer and call it.
[...]

     Is there something wrong (actually wrong, not just "ugly")
about treating the function pointer as an array of bytes and
stringizing the bytes?

     Yes, we all understand that one function pointer might have
many different string representations when done this way, but
surely any of them could reconstitute the original value.

How would that work? Assuming (for simplicity) that function pointers
have the same representation as data pointers, and are 4 bytes in size
(as on an x86). I understand the OP to be asking how to convert an
address 0x23456789 to (effectively) an array of chars:
{'0','x','2','3','4','5','6','7','8','9','\0'}.

What you are suggesting (and what Pete's example seems to show) would
be an array of chars (little-endian): {89, 67, 45, 23, 0}, or {'‰',
'g', 'E','#', '\0'} (obviously, character 0x89 will show up
differently on different systems).

I didn't try it out, so I may be wrong, and just not getting it.

Pete's example isn't even remotely an example of converting the pointer
into a string, regardless of the variable name "string". But what Eric
suggests is what I also suggested, with a code example, in a post which
seems to have disappeared into the ether. If you carefully read what
Eric said, he didn't say to copy the bytes of the pointer. He suggested
"stringizing" the bytes, i.e. converting each byte of the pointer, one
at a time, into characters. On a platform with 8-bit bytes, that could
convert the address 0x23456789 to the string "23456789", but in a
portable fashion, instead of relying on being able to convert it to a
(void *). (Doing this portably is not as simple it might seem at
first glance)
Also, I'm curious, why the OP chose a length of 30 for his character
string. I'm sure it's ID, but it's nice to learn about different
implementations.
If representing the pointer using hexadecimal digits, I think the proper
length of the char array would be

sizeof(int (*)()) * ((CHAR_BIT + 3)/4) + 1


What I'm most curious about is why the OP wants to store a function
pointer in string form, instead of just saving the value in a
pointer variable. The only reason I can think of for doing this
would be if one wanted to save the pointer in a database that didn't
support binary objects. Even there, it might be easier to store the
individual bytes of the pointer in the database as numerical objects.
 
I

Ike Naar

polas said:
Afternoon everyone - I have a question about function pointers. I want
to convert a function pointer to a string (which I will use elsewhere
in the code) and I then want to reconvert this string back to a
function pointer and call it.

I am thinking I can probably do something like
char * thestring=malloc(sizeof(char) * 30));
sprintf(thestring,"%p\0",function pointer);

But how would I convert this string back into a function pointer -
especially in a way which is portable?

#include <stdio.h>
#include <string.h>

int main(void)
{
int (*p1)(const char *s) = puts;
int (*p2)(const char *s);
char string[sizeof p1 + 1];

string[sizeof p1] = '\0';
memcpy(string, &p1, sizeof p1);
memcpy(&p2, string, sizeof p2);
p2("Hello world.");
return 0;
}

Caveat: ``string'' can contain embedded null bytes.
 
J

James Kuyper

pete said:
polas said:
Afternoon everyone - I have a question about function pointers. I want
to convert a function pointer to a string (which I will use elsewhere
in the code) and I then want to reconvert this string back to a
function pointer and call it.

I am thinking I can probably do something like
char * thestring=malloc(sizeof(char) * 30));
sprintf(thestring,"%p\0",function pointer);

But how would I convert this string back into a function pointer -
especially in a way which is portable?

#include <stdio.h>
#include <string.h>

int main(void)
{
int (*p1)(const char *s) = puts;
int (*p2)(const char *s);
char string[sizeof p1 + 1];

string[sizeof p1] = '\0';
memcpy(string, &p1, sizeof p1);

He said that he wanted to convert the pointer to A string. This approach
may, depending upon the representation of p1, create multiple strings in
the array named "string".
 
N

Nick Keighley

If you want to limit yourself to implementations where function pointers
are represented in the same way as other pointers, you can use the %P
format specifier of scanf, which the C99 standard says,
"Matches an implementation-defined set of sequences, which should be the
same as the set of sequences that may be produced by the %p conversion of
the fprintf function."

surely that's "the %p (lower case) format specifier of scanf"
 
M

Morris Keesan

surely that's "the %p (lower case) format specifier of scanf"

Yes. I've never had any occasion where I would have wanted to create a
pointer
from a string representation, so I've never actually used this, and I was
misreading when copying from the standard.
 
P

polas

#include <stdio.h>
#include <string.h>
int main(void)
{
int (*p1)(const char *s) = puts;
int (*p2)(const char *s);
char string[sizeof p1 + 1];
string[sizeof p1] = '\0';
memcpy(string, &p1, sizeof p1);

He said that he wanted to convert the pointer to A string. This approach
may, depending upon the representation of p1, create multiple strings in
the array named "string".
memcpy(&p2, string, sizeof p2);
p2("Hello world.");
return 0;
}

Thanks everyone for the replies - the reason I wanted to do this was
to send the function pointer via TCP/IP to another machine which
simply stored a table of names vs fn pointers, then at some later date
a thread on the first machine will recieve back the function pointer
and jump to the function - the TCP/IP code I am using will just
transmit chars. I know a lot of this is none standard C, which is why
I left the specific details of why I wanted to do this out.

I have achieved this now. I have done this 2 ways - firstly I used the
code posted on here to get it working (and it did, thanks!) and the
other way I did it was to convert the function pointer into a long
long (I am assuming this is 64 bytes, I know this is probably a
foolish assumption) and then transmitting a string representation of
this number and "unpackaging" it at the other end. I feel probably the
first way of doing it (without the long long) is more portable and
safer

Nick
 
B

Barry Schwarz

snip
Thanks everyone for the replies - the reason I wanted to do this was
to send the function pointer via TCP/IP to another machine which
simply stored a table of names vs fn pointers, then at some later date
a thread on the first machine will recieve back the function pointer
and jump to the function - the TCP/IP code I am using will just
transmit chars. I know a lot of this is none standard C, which is why
I left the specific details of why I wanted to do this out.

I wonder what the odds are, that on the later date, function 1 will
still be located at the same address as it was on the date you sent
the data to the other machine. If you have modified the program or
even simply recompiled or relinked it with different options, things
will probably be relocated. Even an OS update could cause the program
to relocated.
 
K

Keith Thompson

Barry Schwarz said:
snip


I wonder what the odds are, that on the later date, function 1 will
still be located at the same address as it was on the date you sent
the data to the other machine. If you have modified the program or
even simply recompiled or relinked it with different options, things
will probably be relocated. Even an OS update could cause the program
to relocated.

If the system guarantees that the address will be used only with the
same execution of the same program that stored it, the odds are
excellent. Otherwise, not so much.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top