get the address of a function??

J

John

Is the following program print the address of the function?

void hello()
{ printf("hello\n");
}

void main()
{
printf("hello function=%d\n", hello);
}

please advice. thanks....
 
R

Richard Heathfield

John said:
Is the following program print the address of the function?

void hello()
{ printf("hello\n");
}

void main()
{
printf("hello function=%d\n", hello);
}

The behaviour of the program is undefined in at least three ways. So - maybe
it will do what you want, and maybe it won't. Maybe it will do what you
want /and/ something else that it doesn't tell you about. No way to tell.
 
I

Ian Collins

Richard said:
John said:




The behaviour of the program is undefined in at least three ways. So - maybe
it will do what you want, and maybe it won't. Maybe it will do what you
want /and/ something else that it doesn't tell you about. No way to tell.
Is there a prize for spotting the three ways?
 
R

Richard Tobin

The behaviour of the program is undefined in at least three ways. So - maybe
Is there a prize for spotting the three ways?[/QUOTE]

No <stdio.h>, two errors in the declaration of main(), passing a
pointer to printf() with a %d format. And despite all that, it will
probably work.

-- Richard
 
K

Keith Thompson

John said:
Is the following program print the address of the function?

void hello()
{ printf("hello\n");
}

void main()
{
printf("hello function=%d\n", hello);
}

No.

"void hello()" is acceptable, but "void hello(void)" is better.

Calling printf with no visible prototype invokes undefined behavior.
The "#include <stdio.h>" is mandatory (even if your compiler doesn't
complain that it's missing).

main returns int, not void. If you learned "void main()" from a
textbook, stop using it and find a better one. The comp.lang.c FAQ is
at <http://www.c-faq.com/>; question 18.10 recommends some good books.
Make it "int main(void)".

printf's "%d" option requires an argument of type int. You're giving
it a function pointer. This invokes undefined behavior.

Since main returns int, you should return an int. Add "return 0;"
after your printf call. This isn't necessarily mandatory, but there's
no reason not to do it.

The printf format for a pointer value is "%p" -- but it can be used
*only* for object pointers, not for function pointers. Actually, "%p"
expects an argument of type void*, and since printf is a variadic
function, an ordinary pointer will not be implicitly converted to
void*; you have to do it yourself.

So the following will work to print the value of an object pointer:

int x;
int *ptr = &x;
printf("ptr = %p\n", (void*)ptr);

*But* there's no defined conversion from a function pointer to void*
(though some compilers may support it as an extension), so this won't
necessarily work for printing the address of your function.

(You can interpret a function pointer value as a sequence of bytes
(unsigned chars) and print their values, but I suspect that's more
than you want to deal with right now.)

Why do you want to do this? If you were to print the address of your
function, what would you do with the information?
 
W

Walter Roberson

No <stdio.h>, two errors in the declaration of main(), passing a
pointer to printf() with a %d format. And despite all that, it will
probably work.

And a pointer might be the wrong size to use with %d, so possibly
only some of the bytes of the pointer will be converted for output.
 
F

Frederick Gotham

John:
Is the following program print the address of the function?

void hello()
{ printf("hello\n");
}

void main()
{
printf("hello function=%d\n", hello);
}


As far as I'm aware, the C Standard doesn't provide a "nice" way to print
function addresses. You could, however, print out the byte values which make
up the address... better than nothing.

void (*const pfunc)(void) = hello;

char unsigned const *p = (char unsigned const*)&pfunc;
char unsigned const *const pover = p + sizeof pfunc;

do printf("%u\n",(unsigned)*p++);
while (pover != p);
 
J

John Bode

John said:
Is the following program print the address of the function?

void hello()
{ printf("hello\n");
}

void main()
{
printf("hello function=%d\n", hello);
}

please advice. thanks....

Well, there are several problems. The %d conversion specifier is the
wrong one to use to print out a pointer value; you should use %p
instead, as it expects a pointer value of type void*. Unfortunately,
you wind up with a type mismatch anyway, as the type of "hello" in the
printf statement is implicitly converted to void (*)(), or a pointer to
a function returning void. Standard C does not allow for conversions
between object pointers (void *) and function pointers (void (*)()) and
vice-versa. Most implementations will do *something* that looks
reasonable, but it's technically not correct.

To top it off, main() returns int, not void. And you don't have a
prototype for printf() in scope (assuming this was the complete program
and not just a fragment).
 
K

Keith Thompson

And a pointer might be the wrong size to use with %d, so possibly
only some of the bytes of the pointer will be converted for output.

Size matters not.

Printing a pointer with a "%d" format invokes undefined behavior.
Printing only some of the bytes is merely one of the infinitely many
possible consequences. (Printing exactly what you expect is, of
course, another, but only if you're unlucky.)
 
D

Default User

Richard said:
No <stdio.h>, two errors in the declaration of main(), passing a
pointer to printf() with a %d format. And despite all that, it will
probably work.

What are the two errors in the declaration of main()?




Brian
 
A

Andrew Poelstra

Is the following program print the address of the function?

void hello()
{ printf("hello\n");
}

void main()
{
printf("hello function=%d\n", hello);
}

please advice. thanks....

Well, it might. Or it might not. Or it might electrocute your dog. If
you don't have a dog, it may connect to a petstore site and get you one.
If you don't have an internet connection, it may fax an ISP and get you
one. If you don't have a fax modem, it might blow up your hard drive and
turn it into one.

In other words, you have undefined behaviour, and anything can happen.

The closest you can get to doing this correctly is:
1. Use "%p" instead of "%d" to print the value of a pointer.
2. Convert all pointers to void* when passing them to varadic functions
like printf(), scanf(), et al.
3. Realize that pointers-to-functions /cannot/ be converted to void*,
unlike pointers-to-objects. So, there's no way for you to do what you
want in standard C. Sorry.
 
J

Jordan Abel

2006-11-02 said:
Size matters not.

Printing a pointer with a "%d" format invokes undefined behavior.

Yeah, but we were talking about "probably will work" - the size/bytes
thing is one of the few aspects of it that has a reasonably large
probability of not working.
Printing only some of the bytes is merely one of the infinitely many
possible consequences. (Printing exactly what you expect is, of
course, another, but only if you're unlucky.)

Personally, I'd use %p with a void * cast - that's about as close to
portable as it gets (it might even be unspecified rather than undefined)
 
K

Keith Thompson

Jordan Abel said:
Yeah, but we were talking about "probably will work" - the size/bytes
thing is one of the few aspects of it that has a reasonably large
probability of not working.


Personally, I'd use %p with a void * cast - that's about as close to
portable as it gets (it might even be unspecified rather than undefined)

I'm reasonably certain it's undefined behavior.

C99 6.3.2.3 defines the behavior of conversions involving pointers.
Since it says nothing about the behavior of a conversion from a
function pointer to void*, the behavior is undefined by omission.

But that raises an interesting point. Consider this:

#include <stdio.h>
int main(void)
{
void (*p)(void) = main;
void *foo = (void*)p;
printf("p = %p\n", p);
return 0;
}

The only relevant constraint on the cast operator (C99 6.5.4) is that
the type name and the operand both have to be scalar. So the cast
invokes undefined behavior, but it doesn't violate any constraint.

It seems a little odd, since it *could* have been treated like other
type mismatches. Attempting to add a function pointer and an integer,
or an object number and a double, is a constraint violation, but
attempting to convert a function pointer to void* isn't.
 
R

Richard Heathfield

Keith Thompson said:

It seems a little odd, since it *could* have been treated like other
type mismatches. Attempting to add a function pointer and an integer,
or an object number and a double, is a constraint violation, but
attempting to convert a function pointer to void* isn't.

<shrug> It's a useful thing to be able to do, and I suspect that the
Committee would have liked to codify it, but felt unable so to do. They do
list it as a common extension, in one of the Appendicicices.
 
S

Simon Biber

Andrew said:
The closest you can get to doing this correctly is:
1. Use "%p" instead of "%d" to print the value of a pointer.
2. Convert all pointers to void* when passing them to varadic functions
like printf(), scanf(), et al.
3. Realize that pointers-to-functions /cannot/ be converted to void*,
unlike pointers-to-objects. So, there's no way for you to do what you
want in standard C. Sorry.

When there's a will, there's a way. (Untested code follows)

void print_func(void (*p)())
{
unsigned char *a = (unsigned char *)&p;
size_t i, n = sizeof p;
for(i = 0; i < n; i++) printf("%02X", (unsigned int)a);
}

If your bytes are greater than 8 bits, you can change the 02 to 04 or 08
in the printf string.

If function pointers are stored in LSB-first (little-endian) format then
the bytes will be the wrong way around.
 
R

Richard Bos

Simon Biber said:
Andrew said:
The closest you can get to doing this correctly is:
1. Use "%p" instead of "%d" to print the value of a pointer.
2. Convert all pointers to void* when passing them to varadic functions
like printf(), scanf(), et al.
3. Realize that pointers-to-functions /cannot/ be converted to void*,
unlike pointers-to-objects. So, there's no way for you to do what you
want in standard C. Sorry.

When there's a will, there's a way. (Untested code follows)

void print_func(void (*p)())
{
unsigned char *a = (unsigned char *)&p;
size_t i, n = sizeof p;
for(i = 0; i < n; i++) printf("%02X", (unsigned int)a);
}

If your bytes are greater than 8 bits, you can change the 02 to 04 or 08
in the printf string.


Or if you have C99, then you can cast to uint_least8_t, and use
PRIxLEAST8 from <inttypes.h>. BTW, I would use sizeof p directly, and
not bother with n. It's a compile-time constant, after all.

Richard
 
J

Jordan Abel

2006-11-02 said:
Keith Thompson said:



<shrug> It's a useful thing to be able to do, and I suspect that the
Committee would have liked to codify it, but felt unable so to do. They do
list it as a common extension, in one of the Appendicicices.

Incidentally - is it legal to convert a function pointer to intptr_t,
when such a type is provided?
 
R

Richard Bos

Jordan Abel said:
Incidentally - is it legal to convert a function pointer to intptr_t,
when such a type is provided?

No. The definition of intptr_t speaks specifically of conversion to and
from void *, not any other type. Since any object pointer can also be
converted to and from void *, that also means that any object pointer
can be converted to a void *, to an intptr_t, back to a void *, and back
to the original type, and the result must compare equal to the original
pointer - but only object pointers.
Function pointers cannot portably be converted either to void *, to any
other object pointer type, or to intptr_t; not directly, and not
indirectly. They _can_ all be converted, losslessly, to one another, but
that isn't helpful if you want to print one.

Richard
 
C

Chris Torek

No. ...
Function pointers cannot portably be converted either to void *, to any
other object pointer type, or to intptr_t; not directly, and not
indirectly. They _can_ all be converted, losslessly, to one another, but
that isn't helpful if you want to print one.

Right.

Fundamentally, this allows implementations to use "fatter" pointers
for "pointer to <function ...>" types than for "pointer to <data
type>" types. The IBM AS/400, at least, makes use of this property.
(Intel x86 compilers used to use it too, back in the days of "near"
and "far" pointers, in various models.)

Note that one can always store the function pointers in data objects
of type "pointer to <function ...>". That is, given some function
T F(arglist), we just declare an actual object:

T (*fp)(arglist); /* e.g., int (*fp)(int, char **) */

and store the pointer to that function in that data object. Now we
take the data object's address:

T (**pfp)(arglist) = &fp;

and we have successfully "smuggled" the function-pointer value inside
a data object, whose address we can print. (Of course, it may be the
*contents* of that address that are in some manner "interesting", but
the address is printable, and is specific to "pfp".)

Now suppose that, for every function F that exists in some given
C program P, we were able to -- in some mechanical manner -- invent
a static-storage-duration pointer of the appropriate type, and set
it to point to F. For instance, if program P contains, among other
things:

int foo(int, char **);
void bar(double);

we would have to create pointers p_foo and p_bar:

int (*p_foo)(int, char **) = foo;
void (*p_bar)(double) = bar;

If we could do this, we would have a data pointer corresponding to
each function pointer, and could substitute the data-pointer values
for every instance of the function pointer value, at the cost of
having to indirect through that data pointer to find the function.
That is, we could rewrite the call:

result = foo(3, &x);

as:

result = (*p_foo)(3, &x);

The question is, can a C compiler do this "mechanically"? The
answer is obviously "yes": every time it encounters an actual
function definition, it emits a definition of the corresponding
pointer -- using the implementation's name space, so something like
__func_foo instead of p_foo -- initialized to point to that function.
Every time it encounters a declaration of a function, it emits a
corresponding declaration (with "extern") for that same pointer.
Every time it encounters a call to a function F, it loads the
pointer from __func_F.

Having done this, the compiler has, in effect, converted all
functions to data objects, which are (in this case) all named
__func_<whatever> instead of just <whatever>. If we were to collect
up all these objects in some manner (say, at link time), and label
them "function descriptors", we could put them in a "function
descriptor table".

Using this technique, a C compiler that was *not* allowed to use
"fat" pointers to point to functions could put the "real" function
pointers -- which could in fact be enormously fat -- into a function
descriptor table, and make the "function pointer" that the programmer
sees be an ordinary data pointer, pointing into the descriptor
table. This is, in fact, exactly what some (but not all) C compilers
do, for architectures on which the underlying machine-code level
function pointers are "fatter" than ordinary data pointers. A C
standard that *required* this would be no more restrictive, in
terms of computing power at least, than the current C standards.
 
H

Herbert Rosenau

Incidentally - is it legal to convert a function pointer to intptr_t,
when such a type is provided?

No, a function pointer can't converted to a data pointer and back.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 

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
474,432
Messages
2,571,681
Members
48,796
Latest member
Greg L.

Latest Threads

Top