main function address

C

CBFalconer

Lew said:
pete wrote:
| Martin Dickopp wrote:
|>
|>> #include <stdio.h>
|>> #include <stdlib.h>
|>>
|>> int main(void)
|>> {
|>> printf("main() at %p\n",(void *)&main);
|>>
|>> return EXIT_SUCCESS;
|>> }
|>
|> Is the cast to `void *' valid?
|
| No.
|
| In N869, it's one of the common extensions.
|
| J.5.7 Function pointer casts
| [#2] A pointer to a function may be cast to a pointer to
| an object or to void, allowing a function to be inspected
| or modified (for example, by a debugger) (6.5.4).
|
| ... which makes it more obviously not part of standard C.

In 9989-1999 (admittedly, just the draft C99 standard, and not
the /actual standard itself), the printf() function documentation
in 7.19.6.3 refers the reader to the fprintf() documentation for
a description of it's input. The fprintf() documentation in
7.19.6.1 says of the %p format

~ p The argument shall be a pointer to void. The value of the
~ pointer is converted to a sequence of printing characters, in
~ an implementation-defined manner.

So, to satisfy the %p format character, the argument to
fprintf()/printf() /must/ be a "pointer to void". Since main is a
"pointer to function returning int", and not a "pointer to void", I
interpreted the documentation as requiring a cast to void pointer.

A better interpretation is that you may not be able to pass the
address of a function to printf. What if you are executing on a
system that dynamically loads and unloads functions, for example.
That address might be a tape volume name and offset, and require
operator intervention to resolve. The data just does not fit into
a void*.
 
A

Arthur J. O'Dwyer

Curious -- I've never considered how implicit conversion rules ought to
play out in the arena of variadic functions... on one hand, pointers to
/anything/ implicitly convert to pointer-to-void, but on the other hand
there's no declaration for the receiving pointer-to-void.

Or, does the implicit conversion apply when the pointer value is extracted
and cast to void * in the receiving function?

I don't understand what you mean. Pointer-to-foo and pointer-to-void
can be implicitly "inter-converted" like this:

foo *pf;
void *pv;

pf = pv; pv = pf;

Likewise, 'pf' passed to a function prototyped as expecting a void
pointer will be implicitly converted. And vice versa.
Variadic functions are by definition not prototyped as expecting
anything in particular in the "..." part. So when you have

printf("foo", pf);

the value of 'pf' is passed to 'printf' as a pointer to foo, no
matter what the function actually expects. Likewise, in

printf("foo", pv);

'pv' is passed as a pointer to void.
Does that clear up your doubts?

HTH,
-Arthur
 
L

Lukasz Wawrzyniak

Undefined behaviour. The standard doesn't define conversions between
function pointers and incomplete or object pointer types. And there is no
guarantee that the type pointer to void is wide enough to be able to
represent the result of such a conversion.

6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any
incomplete or object type...
^^^^^^^^^^^^^^^^^^^^^^^^^

7 A pointer to an object or incomplete type may be converted to
a pointer to a different object or incomplete type...

8 A pointer to a function of one type may be converted to a pointer
to a function of another type and back again; the result shall
compare equal to the original pointer...

Dan

Can a pointer to a function be converted to an integer type such as
size_t such that one could use printf("0x%x\n", (size_t)main); ?

Hmmm, now that I think of it, is it legal (according to the standard)
to convert between pointer and integer types at all?
 
A

Alberto =?iso-8859-1?Q?Gim=E9nez?=

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

El Wed, 07 Apr 2004 10:07:15 +0200, Martin Dickopp escribió:
Is the cast to `void *' valid? I cannot find anything in the standard
which allows a pointer to a function to be converted to type `void *'.

Hi, I'm new to this group, just a couple of days reading. I can see you
are constantly referring to the "Standard" and I've seen in the FAQ that
you must pay for it ($18 electronic document).

All of you have payed for it? shouldn't a "standard" be free?

Thanks in advance and sorry for my english
- --
Alberto Giménez, SimManiac en el IRC
http://www.almorranasozial.es.vg
GNU/Linux Debian Woody 3.0 GnuPG ID: 0x3BAABDE1
Linux registered user #290801
WinError 01E: Timing error - Please wait. And wait. And wait. And wait.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFAdHAp0keCtzuqveERAuOuAJ0cl6hlfaq+ikGVVKTthj/DUgaJVwCaAiRb
4mdlpHHPze7fArdyUEuEe5U=
=uj/E
-----END PGP SIGNATURE-----
 
L

Leor Zolman

I don't understand what you mean. Pointer-to-foo and pointer-to-void
can be implicitly "inter-converted" like this:

foo *pf;
void *pv;

pf = pv; pv = pf;
Yes, of course.
Likewise, 'pf' passed to a function prototyped as expecting a void
pointer will be implicitly converted. And vice versa.

No questions there.
Variadic functions are by definition not prototyped as expecting
anything in particular in the "..." part. So when you have

printf("foo", pf);

the value of 'pf' is passed to 'printf' as a pointer to foo, no
matter what the function actually expects.

And therein lies my question. If pf has type pointer-to-foo, but is printed
using a %p format conversion, that represents a foo* -> void* conversion
without the compiler's "knowledge"... when the internals of printf extract
that argument, it will at some point be "converted" into a void *, but
without any knowledge of what it was "before". So is such an implicit
conversion officially permitted? I've been writing code that does that
forever, and it makes me wonder...

Lew pointed out 7.19.6.1, where it says "the argument [to %p] shall be a
pointer to void. Pete above points out how (explicit) conversion of a
pointer-to-function into a pointer-to-void is a "common extension" (so it
is definitely bad karma to omit the cast with a pointer-to-function)...but
what is the Standard's take on performing no cast whatsoever on a
pointer-to-something-/else/ (not a function, and not void)? IOW, is:
int i, *pi = &i;
printf("%p\n", pi);
conformant?
Likewise, in

printf("foo", pv);

'pv' is passed as a pointer to void.

This is the case that seems well-defined to me, in the case of a %p
conversion.
Does that clear up your doubts?

Does that clear up my question? :)

I'm quite a newbie at Standard-reading, my implementation experience
limited to a very crude subset of pre-C89 C. So please view my questions as
/questions/, rather than any deliberate attempt to suggest a problem with
the Standard. If I do happen to stumble across any problems (and I guess I
may have come close on one or two occasions, even if they weren't
original), that's purely by accident.
-leor
 
A

Arthur J. O'Dwyer

And therein lies my question. If pf has type pointer-to-foo, but is printed
using a %p format conversion, that represents a foo* -> void* conversion
without the compiler's "knowledge"... when the internals of printf extract
that argument, it will at some point be "converted" into a void *, but
without any knowledge of what it was "before". So is such an implicit
conversion officially permitted? I've been writing code that does that
forever, and it makes me wonder...

If you pass a value of type T to a variadic function, and that function
is expecting a value of type U instead, then you have undefined behavior,
unless <some legalese involving cv-qualification>. It's not terribly
unintuitive, is it?


[I think N869 section 7.15.1.1 is wrong when it uses the word
"compatible" to describe what I think is really "having the same
alignment and size restrictions" or something like that. Unless
it was the Committee's intent to have all implementations pass
pointers into variadic functions *as void pointers*, and have an
implicit conversion take place inside 'va_arg'. Experts, please?]


All the exceptions I'm aware of are covered by N869 section 6.2.5.27,
which allows things like

struct foo p;
my_vfunc("actually retrieves a struct bar", &p);


unsigned char *p = <something>;
printf("%p", p);

Since 'unsigned char *' and 'void *' are guaranteed to have the same
representation (at least, according to my interpretation of the Standard;
I know some people think *all* character types are similar to 'void *',
and others think that only *at least one* character type is similar
to 'void *'), this is conforming code.
But it's so easy to add the cast every time and make sure, that it's
just not worth fiddling around with special cases. :)
Lew pointed out 7.19.6.1, where it says "the argument [to %p] shall be a
pointer to void. Pete above points out how (explicit) conversion of a
pointer-to-function into a pointer-to-void is a "common extension" (so it
is definitely bad karma to omit the cast with a pointer-to-function)...but
what is the Standard's take on performing no cast whatsoever on a
pointer-to-something-/else/ (not a function, and not void)? IOW, is:
int i, *pi = &i;
printf("%p\n", pi);
conform[ing]?

No. See above; 'int *' and 'void *' do not necessarily have the
same representation or alignment requirements.

-Arthur
 
L

Leor Zolman

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

El Wed, 07 Apr 2004 10:07:15 +0200, Martin Dickopp escribió:

Hi, I'm new to this group, just a couple of days reading. I can see you
are constantly referring to the "Standard" and I've seen in the FAQ that
you must pay for it ($18 electronic document).

All of you have payed for it? shouldn't a "standard" be free?

I tried using the free version of the "Draft" Standard that's floating
around, and which I guess is legitimately downloadable (although I couldn't
find it last time I looked) for free. But there are enough differences that
I soon (happily) forked over the $18 for my electronic copy of the Real
McCoy.

Compared to what the committee members had to pay in order to cover their
own expenses just to be on the Standard committee, we're getting a bargain
;-)
-leor
 
A

Arthur J. O'Dwyer

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

It would be nice if you could figure out some way to balance your
authentication interests against the readability of your message.
PGP signatures in the text of your message are ugly. (But attachments
are just evil.) Please consider turning off your PGP signature when
posting to Usenet.
El Wed, 07 Apr 2004 10:07:15 +0200, Martin Dickopp escribió:

Hi, I'm new to this group, just a couple of days reading. I can see you
are constantly referring to the "Standard" and I've seen in the FAQ that
you must pay for it ($18 electronic document).

All of you have payed for it? shouldn't a "standard" be free?

That's what I think. ;-) But it costs a lot of money to fly
international experts out to ISO committee meetings to discuss the
state of the C language and suchlike, and it costs a lot of money
to print copies of the standard, and maintain web servers, and pay
salaries to ISO people, and convene meetings to deal with errata
and corrigenda. So I suppose ISO (and member organizations) have
a good reason to charge for copies of the Standard.

If you don't want to buy a copy -- I haven't, and I think I'm
not alone -- you can find electronic versions of N869, the last
public draft of the C99 standard, online somewhere. Google for
"N869".

That is not a proper sig delimiter, as far as I know. The standard
signature delimiter on Usenet is two hyphens followed by a single space
and a newline, like this:
 
B

Ben Pfaff

Arthur J. O'Dwyer said:
That is not a proper sig delimiter, as far as I know. The standard
signature delimiter on Usenet is two hyphens followed by a single space
and a newline, like this:

For what it's worth, that's how PGP escapes a line that begins
with a dash.
 
M

Malcolm

Lukasz Wawrzyniak said:
Can a pointer to a function be converted to an integer type such as
size_t such that one could use printf("0x%x\n", (size_t)main); ?

Hmmm, now that I think of it, is it legal (according to the standard)
to convert between pointer and integer types at all?
No it's not. In the absence of a printf() format specifier, you need

unsigned char buff[sizeof( fptr )]; /* will it choke on sizeof(main)?*/
memcpy(buff, main, sizeof(buff));
for(i=0;i<sizeof(buff);i++)
printf("%02x", (int) buff);
 
M

Martin Dickopp

Malcolm said:
memcpy(buff, main, sizeof(buff));

That's invalid, as a pointer-to-function cannot be converted to
`const void *', the type `memcpy' expects for the second argument.

Martin
 
L

Leor Zolman

If you pass a value of type T to a variadic function, and that function
is expecting a value of type U instead, then you have undefined behavior,
unless <some legalese involving cv-qualification>. It's not terribly
unintuitive, is it?

Actually, it /is/ rather unintuitive to me that in the modern world of the
flat memory model, you can't just pass a foo * in order to print its value
(and be blessed by the Standard) without first casting it to void *.
That's why I wanted to make sure. But if that's the way it is, that's the
way it is. Just one more item for my posting checklist.
-leor
 
K

Keith Thompson

No. Mind you, there is no better way to print the address of a function,
either. Where this works, it works; where it doesn't, nothing else is
likely to.

You can interpret it as an array of unsigned char and print the values
(in, say, hexadecimal).
 
K

Keith Thompson

Alberto Giménez said:
El Wed, 07 Apr 2004 10:07:15 +0200, Martin Dickopp escribió:

Hi, I'm new to this group, just a couple of days reading. I can see you
are constantly referring to the "Standard" and I've seen in the FAQ that
you must pay for it ($18 electronic document).

This has been discussed at great length here and in comp.std.c. Quick
summary: some people agree with you, others don't, and the situation
is unlikely to change. Consult groups.google.com for the old
discussions if you're interested in the arguments.
 
C

Chris Torek

Actually, it /is/ rather unintuitive to me that in the modern world of the
flat memory model, you can't just pass a foo * in order to print its value
(and be blessed by the Standard) without first casting it to void *.

The C standard requires only that memory be "locally flat" (that
is, there can be regions with discontinuities or overlap, as is
the case on the 80x86 with its 16-byte "segments" addressing up to
1 megabyte of RAM, with the CS, DS, ES, and SS registers "overlapping"
data pointers in that odd manner, so that you get phys_addr =
(segment << 4) + offset).

This has nothing to do with the cast, though, whose purpose is
to make the types match. The underlying representation of any
given value is allowed to depend on its type. Just as 1.0f (a
32-bit float) and 1 (a 32-bit int) have different bit patterns
even though they have the same value, it is possible that:

int *ip;
void *vp;
...
vp = ip;

puts a different bit pattern into vp than is in ip. C values always
have types, and -- in the abstract machine defined by the standard
-- you *must* specify the type at all times. Converting a value
of one type to an otherwise-equal value of some other type is
allowed to change the representation, and in fact does so on some
machines for some data types.

Twenty years ago, it was common for different pointer types to have
different underlying representations (on some machines), just as
today's machines still have different representations for int vs
float. With 64-bit architectures becoming more common -- and with
the same pressure for backwards compatibility that has always been
there -- it seems likely to me that it will become common again.
 
C

CBFalconer

Leor said:
.... snip ...

And therein lies my question. If pf has type pointer-to-foo, but
is printed using a %p format conversion, that represents a foo*
-> void* conversion without the compiler's "knowledge"... when
the internals of printf extract that argument, it will at some
point be "converted" into a void *, but without any knowledge of
what it was "before". So is such an implicit conversion
officially permitted? I've been writing code that does that
forever, and it makes me wonder...

It is not permitted. The printf has no knowledge of what is
passed as parameters, other than what it is told in the format
string. So there can be no implicit conversions there. Thus it
is imperative to pass things that agree with the format string,
and therefore you must cast the pointer to a void* at function
call time.

The normal integer promotions are another matter, and occur for
all parameters passed to any functions. They can NEVER lose
information, and serve to keep the stack (assuming there is a
stack) properly aligned, among other things. Thus you cannot pass
a char, it is always promoted to int. You can, however, tell
printf how to interpret that int. Similarly you can't pass a
short, or a float, without promotions.
 
L

Leor Zolman

It is not permitted. The printf has no knowledge of what is
passed as parameters, other than what it is told in the format
string. So there can be no implicit conversions there. Thus it
is imperative to pass things that agree with the format string,
and therefore you must cast the pointer to a void* at function
call time.

The normal integer promotions are another matter, and occur for
all parameters passed to any functions. They can NEVER lose
information, and serve to keep the stack (assuming there is a
stack) properly aligned, among other things. Thus you cannot pass
a char, it is always promoted to int. You can, however, tell
printf how to interpret that int. Similarly you can't pass a
short, or a float, without promotions.

Thanks all...the integral stuff I had a pretty good handle on, and now
I think I'll do much better with the pointer conversion rules. I'll
probably do even better after tomorrow, which is when I'll get the
chance to properly digest Chris's post ;-)
-leor
 
J

John Tsiombikas (Nuclear / the Lab)

Actually, it /is/ rather unintuitive to me that in the modern world of the
flat memory model, you can't just pass a foo * in order to print its value
(and be blessed by the Standard) without first casting it to void *.

I think that qualifies as an instance of the old "All world is a VAX"
syndrom :)
Sure, our personal computers are blessed by flat memory models the last
few years but C is not a language for PC-or-greater programming. A lot
of embedded systems still use segmented memory models.
 
O

Old Wolf

Malcolm said:
Lukasz Wawrzyniak said:
Can a pointer to a function be converted to an integer type such as
size_t such that one could use printf("0x%x\n", (size_t)main); ?

Hmmm, now that I think of it, is it legal (according to the standard)
to convert between pointer and integer types at all?
No it's not. In the absence of a printf() format specifier, you need

unsigned char buff[sizeof( fptr )]; /* will it choke on sizeof(main)?*/

Yes, you cannot do sizeof on a function pointer.
memcpy(buff, main, sizeof(buff));
^^^^^^^
for(i=0;i<sizeof(buff);i++)
printf("%02x", (int) buff);


void *memcpy(void *, void *, size_t);

You cannot convert a function pointer to a void pointer portably,
as discussed earlier in this thread. I think you will either have
to rely on implementations allowing this conversion, or not print
out function addresses.

BTW - are there any known implementations where function pointers
cannot be converted to (void *) and back ?
 
B

Barry Schwarz

It is not permitted. The printf has no knowledge of what is
passed as parameters, other than what it is told in the format
string. So there can be no implicit conversions there. Thus it
is imperative to pass things that agree with the format string,
and therefore you must cast the pointer to a void* at function
call time.

The normal integer promotions are another matter, and occur for
all parameters passed to any functions. They can NEVER lose
information, and serve to keep the stack (assuming there is a
stack) properly aligned, among other things. Thus you cannot pass
a char, it is always promoted to int. You can, however, tell
printf how to interpret that int. Similarly you can't pass a
short, or a float, without promotions.

Are you saying that calling a von-variadic function with a proper
prototype in scope will still have char, short, and float promoted?


<<Remove the del for email>>
 

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,141
Messages
2,570,817
Members
47,366
Latest member
IanCulpepp

Latest Threads

Top