main function address

B

Barry Schwarz

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

If you can't cast it to void*, now can you cast it to unsigned char *?


<<Remove the del for email>>
 
K

Keith Thompson

CBFalconer said:
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.

You can never pass a char, short, or float to printf, but the default
argument promotions are not performed for calls to prototyped
functions (except for arguments corresponding to a "..." in the
prototype).

For example, given the following:

void func(char c) { /* blah blah */ }
char arg = 'x';
func(arg);

no conversion is performed on the argument. (It may be that the
argument-passing convention passes the argument in, say, a 32-bit
register, but there's no conversion as far as the language is
concerned.)
 
C

Chris Torek

Yes, you cannot do sizeof on a function pointer.

Er, you mean "on a function" -- it is OK to apply it to a value of
type "pointer to function ..." (where ... is some valid type).

In other words, given:

int f(void);

the sequence:

sizeof f

is an error (and requires a diagnostic), while:

sizeof &f

is OK and produces the same result as sizeof(int (*)(void)).
BTW - are there any known implementations where function pointers
cannot be converted to (void *) and back ?

IBM AS/400; IBM PC ("compact" model if I remember the name right
-- 16-bit data pointers, 32-bit function pointers). There are no
doubt others, although finding compilers that even claim conformance
(much less achieve it) seems less likely for those. :)
 
D

Dan Pop

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

But the output need not be meaningful. The trivial case is when you get
the byte order wrong, but the infamous (and mythical) padding bits can
turn the output into pure garbage (in theory, at least).

Dan
 
D

Dan Pop

No it's not.

Of course it is.
In the absence of a printf() format specifier, you need

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

Yes, of course it chokes on sizeof(main): it's a constraint violation.

Constraints

1 The sizeof operator shall not be applied to an expression that
has function type or an incomplete type, to the parenthesized
name of such a type, or to an expression that designates a
bit-field member.
memcpy(buff, main, sizeof(buff));
^^^^
Nonsense. Even on platforms defining the conversion between function
pointers and void pointers, this doesn't yield the expected result: you're
copying sizeof buff bytes from the main function body (on von Neumann
architectures: single address space for code and data, and random
data bytes on Harvard architectures: code and data lie in different
address spaces).

Your ignorance is only matched by your stupidity.

The right code for what you want to do is:

unsigned char buff[sizeof fptr ];
fptr foo = main;
memcpy(buff, &foo, sizeof buff);

Dan
 
D

Dan Pop

In said:
If you can't cast it to void*, now can you cast it to unsigned char *?

You can, if you assign it first to a pointer to function, which is an
ordinary object whose address can be converted to unsigned char * (or
even to void *, but this doesn't help, in context):

fptr foo = main;
unsigned char *p = (unsigned char *)&foo;

Now, you can use p to access the representation of the value of foo.

Dan
 
D

Dan Pop

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

IBM AS/400; IBM PC ("compact" model if I remember the name right
-- 16-bit data pointers, 32-bit function pointers).[/QUOTE]

Nope, that's the "medium" memory model. The "compact" model has little
code and lots of data.

The IBM PC has another "interesting" memory model, the "small" memory
model, which behaves like a Harvard architecture where both data and
code address spaces have the same size, converting function pointers
to data pointers and back works, but using the result of converting
a function pointer to a data pointer to access the function's code bytes
doesn't yield the (naively) expected results (you're reading from the data
address space, not from the code address space). The high end PDP-11
models behaved the same way (the I and D address spaces).

Dan
 
L

Leor Zolman

I think that qualifies as an instance of the old "All world is a VAX"
syndrom :)

Note I did (reluctantly) accept reality two sentences later.

Do VAX people really think that way? The only time I've worked near a VAX
was at MIT LCS, and while folks there were excited to get one (1978), I
think they did pretty well keeping an open mind about other architectures.
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.

Okay, but I guess the point I was trying to make is that it may not be
"intuitive" for everyone that segmented memory models and void * -> Foo*
conversions represent something akin to an irresistable force meeting an
immovable object. I'm sure it /is/ intuitive, now, for everyone who's
already dealt with the issue in one way or another, but I hadn't ;-)
-leor
 
J

Jeremy Yallop

Barry said:
If you can't cast it to void*, now can you cast it to unsigned char *?

You can't cast a function pointer to unsigned char * and expect
meaningful results. You can, however, cast the address of a function
pointer to unsigned char * in order to inspect the representation,
since a function pointer is just an object.

Jeremy.
 
R

Richard Bos

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

Myes, you can; but where pointers are sufficiently unusual for the above
not to work, is that likely to give usefully interpretable values? Maybe
so.

Richard
 
L

Lew Pitcher

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

Dan Pop wrote:

|
|
|>On Thu, 08 Apr 2004 01:43:44 GMT, Keith Thompson <[email protected]>
|>wrote:
|>
|>
|>>[email protected] (Richard Bos) writes:
|>>
|>>>
|>>>
|>>>>
|>>>>
|>>>>>#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. 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).
|>
|>If you can't cast it to void*, now can you cast it to unsigned char *?
|
|
| You can, if you assign it first to a pointer to function, which is an
| ordinary object whose address can be converted to unsigned char * (or
| even to void *, but this doesn't help, in context):
|
| fptr foo = main;
| unsigned char *p = (unsigned char *)&foo;
|
| Now, you can use p to access the representation of the value of foo.

OK, so now I understand.

Anyone want to tell me /why/ the standard makes such contortions necessary?

(Not that I care in the practical sense; I don't normally code programs such
that I have to print the value of the address of a function)


- --
Lew Pitcher
IT Consultant, Enterprise Application Architecture,
Enterprise Technology Solutions, TD Bank Financial Group

(Opinions expressed are my own, not my employers')
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)

iD8DBQFAdVvGagVFX4UWr64RAodAAJ0Wsl2PQIRvdYeUEtsCm39+cGKDdwCg4pRB
IVE0b8Xp5qunYCeX9wMFCr4=
=+fzk
-----END PGP SIGNATURE-----
 
D

Dan Pop

In said:
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
;-)

In your opinion, how many of them had to pay it from their own pocket? ;-)

Dan
 
T

Thomas Matthews

Sweety said:
hi,
Is main function address is 657.
its show in all compiler.
No, it is not.
try it & say why?
My compiler and linker package allows me to place the
"main" function at any address I choose. Where do you
want it?

At the moment, I have the main() function set to
0x00000. On another platform, I'll set it to 0x14000,
due to other junk residing at the other locations.

On another platform, the operating system places the
executable at an address that the OS finds convienient.
The location of main() depends on what other programs
or stuff is residing in memory at the same time. I
bet if I remove the virus checker, the location of main
will change.


--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
C

CBFalconer

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

As usual, it depends. For most systems char will occupy only a
portion of an (assumed) aligned stack unit, so it will be
expanded. For some, the same applies to shorts. Ints are
supposed to represent the most efficient storage unit for the
actual machine. On an x86 for example, stack access would be
seriously impeded if the stack was not kept on 4 byte boundary
alignment. On many architectures it would be simply impossible.
Always assuming there is a stack.
 
D

Dan Pop

In said:
Dan Pop wrote:

| You can, if you assign it first to a pointer to function, which is an
| ordinary object whose address can be converted to unsigned char * (or
| even to void *, but this doesn't help, in context):
|
| fptr foo = main;
| unsigned char *p = (unsigned char *)&foo;
|
| Now, you can use p to access the representation of the value of foo.

OK, so now I understand.

Anyone want to tell me /why/ the standard makes such contortions necessary?

The easy way out for printf would be something like %q which expects a
pointer to a void function taking no arguments. However, given that %p
itself is virtually never used in real world programs, and that
%lx or %llx do work on the pointer converted to the appropriate integer
type, there is little point on adding %q.

As for conversions between function pointers and void pointers not being
defined, the reason is related to the existence of certain architectures
that would require extremely wide void pointers (and, automatically,
character pointers) if function pointers were to be convertible to void
pointers without loss of information (see below). Such conversions
are seldom needed, but all the ordinary applications dealing with
character pointers and void pointers would have to pay the price,
on such platforms.

Void pointers and all the other pointers to incomplete types are,
essentially, data pointers (they are supposed to hold object addresses,
unless they are null pointers). OTOH, functions are NOT objects. On
Harvard architectures, the difference is more than purely conceptual:
data (objects) and code (functions) lie in different address spaces and
the same address value has different meanings, depending on whether it's
a data address or a code address. So, converting a function pointer to
a data pointer doesn't make much sense.

Then, of course, there are the oddball architectures, like the AS/400,
where pointer values are not mere addresses, but they encode plenty of
other information. AFAIK, on at least one C implementation for the
AS/400, data pointers are 16 bytes, while function pointers are 128 bytes.
The C programmers working with it must be quite happy that their void
pointers need a mere 16 bytes, instead of 8 times as much :)

To summarise, it is only on von Neumann architectures (code and data lie
in the same address space) that conversions between function pointers and
data pointers actually make sense. By letting such conversions completely
undefined, the standard allows the implementors to do the right thing on
such platforms and the programmers to take advantage of it, without
writing code that requires any kind of diagnostics. That's why your
original example is likely to work as intended, without any diagnostics,
on most hosted implementations. Hopefully, the AS/400 C compilers would
diagnose it.

Dan
 
L

Leor Zolman

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.

That's the part I did not realize. Given this fact, the rules make a lot
more sense. Thanks,
-leor
 
D

Dan Pop

In said:
Note I did (reluctantly) accept reality two sentences later.

Do VAX people really think that way? The only time I've worked near a VAX
was at MIT LCS, and while folks there were excited to get one (1978), I
think they did pretty well keeping an open mind about other architectures.

The famous expression refers to people who have never used or programmed
on anything but VAXen. Therefore, they got to assume that programming on
any other computer is like programming on a VAX. It's people who have
started their computing experience during the early 80's that are
affected. Until the late 80's, the VAX was the most popular computing
platform: without the limitations of the PDP-11 and without the price tag
of a mainframe, yet powerful enough for most computing problems of its
days. Most universities, research labs and small to medium businesses
were VAX shops any many people have never been exposed to any other
(serious) computing platforms during that decade. As a result, their
code blindly assumed that all implementations must behave like the ones
targeting the VAX (linear address space, 32-bit int's, long's, pointers).

When one of them had to switch to a different computing platform, he
discovered, quite surprised, that all the world is not a VAX and his
coding habits had to be revised.

History repeated the next decade, with the PC (MSDOS and 16-bit Windows)
taking the place of the VAX and, mutatis mutandis, the syndrome became
"all world is a PC". Questions about far pointers and allocating more
than 64K have plagued c.l.c until the late nineties.

Dan
 
L

Leor Zolman

The famous expression refers to people who have never used or programmed
on anything but VAXen.
....

Sorry, Dan, by omitting a smiley there I inadvertently caused you some
extra typing. I did actually catch the original drift, and that response
was my lame attempt at being cute. Folks there /really were/ pumped about
that VAX, though... ;-)
-leor
 
K

Keith Thompson

Myes, you can; but where pointers are sufficiently unusual for the above
not to work, is that likely to give usefully interpretable values? Maybe
so.

Maybe yes, maybe no. The hexadecimal string you get by interpreting a
function pointer as an array of unsigned bytes isn't going have any
useful portable interpretation, but it might be useful in the context
of platform-specific knowledge about the underlying representation.

There's little or no *portable* use for examining the bytes that make
up a function pointer, but it might be useful for diagnosing bizarre
problems (e.g., within a debugger).
 
P

pete

CBFalconer said:
As usual, it depends.

The answer to the question, is "No".

N869
6.5.2.2 Function calls
[#7] If the expression that denotes the called function has
a type that does include a prototype, the arguments are
implicitly converted, as if by assignment, to the types of
the corresponding parameters, taking the type of each
parameter to be the unqualified version of its declared
type.

[#8] No other conversions are performed implicitly;
 

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

Forum statistics

Threads
474,141
Messages
2,570,817
Members
47,366
Latest member
IanCulpepp

Latest Threads

Top