size of a function

J

Joe Wright

Robert said:
Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.

Robert Gamble
Really? Given 'int foo(int);' somewhere the compiler will see 'foo' as
the address of a function. There is no information anywhere as to how
many bytes of memory are required to house foo().
 
K

Keith Thompson

Joe Wright said:
Robert Gamble wrote: [...]
Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.
Robert Gamble
Really? Given 'int foo(int);' somewhere the compiler will see 'foo' as
the address of a function. There is no information anywhere as to how
many bytes of memory are required to house foo().

Yes, really, you can apply sizeof to a function pointer. The result
is the size of the pointer, not the size of the function.

Note that "sizeof foo" won't do this, since the argument to sizeof is
one of the contexts in which a function name is *not* implicitly
converted to a pointer.

For example:

#include <stdio.h>

int foo(int i)
{
}

int main(void)
{
int (*foo_ptr)(int) = foo;
printf("sizeof foo_ptr = %d\n", (int)sizeof foo_ptr);
return 0;
}

On one implementation I tried, this prints
sizeof foo_ptr = 4

On another, it prints
sizeof foo_ptr = 8
 
R

Robert Gamble

Joe said:
Really? Given 'int foo(int);' somewhere the compiler will see 'foo' as
the address of a function. There is no information anywhere as to how
many bytes of memory are required to house foo().

foo is of type function, it is not a function pointer.

Robert Gamble
 
J

Joe Wright

Keith said:
[ snip ]

If it were useful to compute the size of a function, these particular
issues could be solved. We can take the address of a function, after
all. Even if the function is inlined, perhaps multiple times, the
address gives you something through which the function can be called
with arbitrary arguments.

Having said that, the other reasons why the size of a function is not
useful are perfectly valid.

I asked my gcc implementation about the size of main.

#include <stdio.h>
int main(void) {
printf("The size of main seems to be %d.\n",
(int)sizeof main);
return 0;
}

The size of main seems to be 1.
 
A

Alexei A. Frounze

Dik T. Winter said:
You can't malloc() memory and copy a function
into (or from!) it, because functons are not data: C is
specified in such a way that it can be implemented even if
instructions and data occupy completely different address
spaces, perhaps with completely different characteristics.

Indeed, suppose the data is organised with CHAR_BIT=9, but compiled
functions use 8-bit bytes. In that case you would in general not
even get a value that as some reasonable meaning.[/QUOTE]

Actually, since void* and void(*)() are different types of pointers and in
general point to different address spaces (data and code, respectively),
it's fine to calculate difference of function pointers and get the distance
between the two in whatever the minimal addressable unit (MAU) is in the
program address space, similarly to data pointers and data space. That's
just fine. I know a platform where data space MAU is 16-bit long and program
space MAU is 8-bit long. It would be OK to get the appropriate amount of
MAUs in their respective address spaces. And data MAU not necessarily needs
to equal to program MAU... That's the user's problem if they use data MAUs
for program and vice versa, just like using void* in place of void(*)().

Alex
 
K

Keith Thompson

Joe Wright said:
Keith said:
[ snip ]
If it were useful to compute the size of a function, these particular
issues could be solved. We can take the address of a function, after
all. Even if the function is inlined, perhaps multiple times, the
address gives you something through which the function can be called
with arbitrary arguments.
Having said that, the other reasons why the size of a function is not
useful are perfectly valid.

I asked my gcc implementation about the size of main.

#include <stdio.h>
int main(void) {
printf("The size of main seems to be %d.\n",
(int)sizeof main);
return 0;
}

The size of main seems to be 1.

Here's what the gcc documentation says about this:

In GNU C, addition and subtraction operations are supported on
pointers to `void' and on pointers to functions. This is done by
treating the size of a `void' or of a function as 1.

A consequence of this is that `sizeof' is also allowed on
`void' and on function types, and returns 1.

The option `-Wpointer-arith' requests a warning if these
extensions are used.

I can understand the idea of allowing pointer arithmetic on void*
(though I think it's a bad idea), but it's difficult to think of a
good use for pointer arithmetic on function pointers.
 
A

Alexei A. Frounze

....
I can understand the idea of allowing pointer arithmetic on void*
(though I think it's a bad idea), but it's difficult to think of a
good use for pointer arithmetic on function pointers.

Poking/patching/modifying the program on the fly by writing program space
MAUs to program memory using function pointers...

E.g.:

void MyBrokenFxn()
{
//...
}

ProgMAU aNewCode[] = {0xC3/*ret*/};

void (*p)() = &MyBrokenFxn;

int i;
for (i=0; i<sizeof(ProgMAU)/sizeof(ProgMAU[0]); i++)
p = aNewCode;


Btw, any decent general purpose OS must be able to load programs (I, stress,
the code) to program memory. Even if we leave along all those protection
mechanisms and other CPU/OS-specific things that are due, the sole process
of modifying program memory is implementation specific in C because C
doesn't support this thing in general (unless the program and data memories
are the same thing or are somehow mapped into each other). Don't you find
this funny about C and Unix? Unix was written mostly in C but at the same
time there was no support for this regular operation (modifying program
memory) in C :)
This was left to the ASM...

Alex
 
K

Keith Thompson

Alexei A. Frounze said:
...
I can understand the idea of allowing pointer arithmetic on void*
(though I think it's a bad idea), but it's difficult to think of a
good use for pointer arithmetic on function pointers.

Poking/patching/modifying the program on the fly by writing program space
MAUs to program memory using function pointers...

E.g.:

void MyBrokenFxn()
{
//...
}

ProgMAU aNewCode[] = {0xC3/*ret*/};

void (*p)() = &MyBrokenFxn;

int i;
for (i=0; i<sizeof(ProgMAU)/sizeof(ProgMAU[0]); i++)
p = aNewCode;


You have a type conflict in the assignment. p is a
pointer-to-function, so p would be of a function type; presumably
even gcc won't let you assign to that.

On platforms where it makes sense, you can always convert between
pointer-to-function and, say, unsigned char* (which is, strictly
speaking, a constraint violation, but a reasonable extension).

If you're going to read or write values through the pointer, you're
going to have to convert it to an object pointer type anyway.
Btw, any decent general purpose OS must be able to load programs (I, stress,
the code) to program memory. Even if we leave along all those protection
mechanisms and other CPU/OS-specific things that are due, the sole process
of modifying program memory is implementation specific in C because C
doesn't support this thing in general (unless the program and data memories
are the same thing or are somehow mapped into each other). Don't you find
this funny about C and Unix? Unix was written mostly in C but at the same
time there was no support for this regular operation (modifying program
memory) in C :)
This was left to the ASM...

There's no reason you can't do that kind of thing in C (though not in
portable C). Any such code will almost inevitably invoke undefined
behavior, but OS code is allowed to do that. (I suppose I'm assuming
that code and data are in the same address space; if they aren't, the
implementation can provide extensions.)
 
T

Tim Rentsch

Lawrence Kirby said:
Function pointers can be cast to other function pointer types but they
must be cast back to the original type before the funciton is called.

Probably it's true that function pointers must be converted just to a
type that is compatible with the type of the function being called,
not necessarily the exact type of the function. This guarantee is
not stated explicitly, but it is implied: 6.3.2.3 p8, 6.5.2.2 p9.

[Note: glossing over the distinction between a function type and
a type that is a pointer to said function type, which the language
rules make rather easy to do.]
 
M

Mabden

Keith Thompson said:
Eric Sosman said:
Robert said:
Please provide context when posting a followup so we know what you are
responding to.
maadhuu wrote:

i don't think there is anything wrong in knowing such things , not
necessary that it should be always used somewhere,
Agreed, if you don't ask you might never know.

also why is it a violation ??
Because the Standard says so.

Robert's answer is correct, but unsatisfactory. The
obvious follow-up is "But *why* does the Standard say so?" [snip]

Second, the very notion of "the size" of a function is
rather slippery. What if the function has been expanded in-
in five or six places? Is "the size" the total size of all
expansions? If so, it might not be a compile-time constant
if the function is inlined in different translation units.
If "the size" is the memory footprint of one expansion, which
one is it? Note that different in-line expansions may well
generate different instruction counts. What if the optimizer
intermixes the in-line expansion's instructions with those of
the caller? What if the optimizer produces some instructions
that are not strictly attributable to either the caller or
to the expanded function? What if some optimizations occur
at run-time (think "JIT compiler"), using profiling data
gathered during the run, data that might vary from one run
to the next?

If it were useful to compute the size of a function, these particular
issues could be solved. We can take the address of a function, after
all. Even if the function is inlined, perhaps multiple times, the
address gives you something through which the function can be called
with arbitrary arguments.

Having said that, the other reasons why the size of a function is not
useful are perfectly valid.

We agree so often that you only rarely have to deal with my nonsense,
but I think we can both appreciate that code-bloat can be a problem in
many companies.

In fact I remember a story from back when MicroSoft (capital S) was
attempting to work with IBM and their progress was counted by LOC
measurement. MS had a problem with this, since they preferred
streamlining code to filling up code with arbitrary bloat by whatever
methods they could find (I could mention some, like extraneous comments,
multi-lining code that could be written more concisely, etc - but I
WON'T!)

I believe that there is a VALID reason to have SOF verification!

This is not just a programmer problem, or a program fault; managers need
to be held accountable, as well as companies. It takes a company to
create a program, never forget! Most people, many of them managers, that
I have "spoken" to have agreed that SOF verification does not even go
far, enough!

A company shouldn't have a posse of unused subroutines floating around
without proper version control, spawning random unused processes at
will!

Perhaps a hacker-after program that can eliminate the bloat several
months after it "shows" is
acceptable to some, but not to me! A more bloat-aware metric needs to be
perfected! Why is it always the program's fault, and never the
progRAMer. Why can't there be some kind of "after-bloat check" that the
program could have access to?! Is it because the program is a beta?! We
need to understand that beta program bloat is not a shameful NOR
uncommon occurrence! Many programs spawn processes in their beta stage.
It is just a fact, and managers just need to come online and deal with
it. If we don't deal with beta code-bloat, at the alpha site, then we
will propagate early release without a doubt!

There are many problems our companies sweep into the bit-bucket, but the
time has come to address these issues!
 
L

Lawrence Kirby

On Mon, 05 Sep 2005 17:50:02 +0000, Keith Thompson wrote:

....
Um, maybe you shouldn't post before you've had your coffee? :cool:}

sizeof always yields a result in bytes. Pointer subtraction yields a
result in units of the type being pointed at. (I know you know that.)

Thank you, I meant pointer difference. I'm not sure how it turned into
sizeof. :)

Lawrence
 
A

Alexei A. Frounze

Keith Thompson said:
ProgMAU aNewCode[] = {0xC3/*ret*/};

void (*p)() = &MyBrokenFxn;

int i;
for (i=0; i<sizeof(ProgMAU)/sizeof(ProgMAU[0]); i++)
p = aNewCode;


You have a type conflict in the assignment. p is a
pointer-to-function, so p would be of a function type; presumably
even gcc won't let you assign to that.

On platforms where it makes sense, you can always convert between
pointer-to-function and, say, unsigned char* (which is, strictly
speaking, a constraint violation, but a reasonable extension).


Indeed, p is pointer to function...

What's interesting, gcc compiles the following on x86:
void (*p)()=(void(*)())1;
printf ("%lu\n", (unsigned long)(p+1));
and the printf prints 2. It's not assigning to *(char*)p, but at least 1 can
be added to p as I might expect it.

Actually, even the following compiles with gcc (with -Wall) and gives 10:
void (*p)()=(void(*)())1;
void (*q)()=(void(*)())11;
printf ("%lu\n", (unsigned long)(q-p));

So, is it that gcc supports some function pointer arithmetics?

And the more interesting thing is that the following two lines result in
different errors:
p[1] = 0; // error: subscripted value is neither array nor pointer
*(p+1) = 0; // error: invalid lvalue in assignment
First says what it says about p (though p *is* a pointer, albeit not pointer
to data) while second says *(p+1) is bad lvalue (the same error is issued
for *p = 0; too).
Quite odd that p[1] and *(p+1) are treated differently.
If you're going to read or write values through the pointer, you're
going to have to convert it to an object pointer type anyway.
Right.


There's no reason you can't do that kind of thing in C (though not in
portable C). Any such code will almost inevitably invoke undefined
behavior, but OS code is allowed to do that. (I suppose I'm assuming
that code and data are in the same address space; if they aren't, the
implementation can provide extensions.)

That's the point.

Alex
 
K

Keith Thompson

Mabden said:
We agree so often that you only rarely have to deal with my nonsense,
but I think we can both appreciate that code-bloat can be a problem in
many companies.
[snip]

I didn't want to quote everything you wrote. To summarize, you argue
that it's useful to know the size of a function, to measure and avoid
code bloat.

I actually agree, but I think the right way to do that is to use
external tools that examine object files and/or executables.

Knowing the code size of a function can be useful, but I don't see how
it can be useful to compute it within the program. Any code that
computes and checks this would only *add* to code bloat. It also
can't easily iterate over all the functions in the program; there's no
way for a program that uses a given library to know all the functions
(visible or not) that make up the library. An external tool can
easily do all of this.

I'm not sure how useful this is, but to the extent that it's useful it
should be done by external tools.
 
K

Kenneth Brody

Keith Thompson wrote:
[...]
I didn't want to quote everything you wrote. To summarize, you argue
that it's useful to know the size of a function, to measure and avoid
code bloat.

I actually agree, but I think the right way to do that is to use
external tools that examine object files and/or executables.

Knowing the code size of a function can be useful, but I don't see how
it can be useful to compute it within the program. Any code that
computes and checks this would only *add* to code bloat. It also
can't easily iterate over all the functions in the program; there's no
way for a program that uses a given library to know all the functions
(visible or not) that make up the library. An external tool can
easily do all of this.
[...]

Also, given optimizers, it may not be possible to give you the size of
a function. I have seen compilers generate code which was shared by
more than one function, when those functions ended the same way.

For example:

int foo()
{
int i,j;
... lots of code
for ( i=0, j=0 ; i < 10 ; i++ )
j += foobar(i);
return(j);
}

int bar()
{
int i,j;
... lots of code, but different than foo()
for ( i=0, j=0 ; i < 10 ; i++ )
j += foobar(i);
return(j);
}

The end of bar() would not include the for loop, the calls to foobar(),
or the return. Rather, there would be a JMP to the code within foo().

Would you consider that shared machine code part of bar()? If not, would
you consider foo() "bloated" because it was that much larger than bar()?

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
J

Joe Wright

Keith said:
Joe Wright said:
Robert Gamble wrote:
[...]
Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.
Robert Gamble

Really? Given 'int foo(int);' somewhere the compiler will see 'foo' as
the address of a function. There is no information anywhere as to how
many bytes of memory are required to house foo().


Yes, really, you can apply sizeof to a function pointer. The result
is the size of the pointer, not the size of the function.

Note that "sizeof foo" won't do this, since the argument to sizeof is
one of the contexts in which a function name is *not* implicitly
converted to a pointer.

For example:

#include <stdio.h>

int foo(int i)
{
}

int main(void)
{
int (*foo_ptr)(int) = foo;
printf("sizeof foo_ptr = %d\n", (int)sizeof foo_ptr);
return 0;
}

On one implementation I tried, this prints
sizeof foo_ptr = 4

On another, it prints
sizeof foo_ptr = 8

#include <stdio.h>

int foo(void) {
return 0;
}

int main(void)
{
printf("sizeof foo is %d bytes.\n", (int)sizeof foo);
printf("sizeof printf is %d bytes.\n", (int)sizeof printf);
return 0;
}

At my house, gcc 3.1 prints 1 in both cases.

We agree that the sizeof a pointer is whatever the size of a pointer is.
My point is that the size of a function is not available. The compiler
cannot know it.
 
K

Keith Thompson

Joe Wright said:
Keith said:
Joe Wright said:
Robert Gamble wrote: [...]

Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.
Robert Gamble


Really? Given 'int foo(int);' somewhere the compiler will see 'foo' as
the address of a function. There is no information anywhere as to how
many bytes of memory are required to house foo().
Yes, really, you can apply sizeof to a function pointer. The result
is the size of the pointer, not the size of the function.
Note that "sizeof foo" won't do this, since the argument to sizeof is
one of the contexts in which a function name is *not* implicitly
converted to a pointer.
For example:
#include <stdio.h>
int foo(int i)
{
}
int main(void)
{
int (*foo_ptr)(int) = foo;
printf("sizeof foo_ptr = %d\n", (int)sizeof foo_ptr);
return 0;
}
On one implementation I tried, this prints
sizeof foo_ptr = 4
On another, it prints
sizeof foo_ptr = 8

#include <stdio.h>

int foo(void) {
return 0;
}

int main(void)
{
printf("sizeof foo is %d bytes.\n", (int)sizeof foo);
printf("sizeof printf is %d bytes.\n", (int)sizeof printf);
return 0;
}

At my house, gcc 3.1 prints 1 in both cases.

Yes, I get the same result. With "-pedantic", I also get:

tmp.c:9: warning: invalid application of `sizeof' to a function type
tmp.c:10: warning: invalid application of `sizeof' to a function type
We agree that the sizeof a pointer is whatever the size of a pointer
is. My point is that the size of a function is not available. The
compiler cannot know it.

Right, none of this is in dispute.

Looking at the quoted text above, Robert Gamble wrote:

Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.

You replied:

Really?
[...]

And I replied:

Yes, really, you can apply sizeof to a function pointer.
[...]

Perhaps you thought that Robert Gamble was saying that applying sizeof
to a function pointer would give you the size of the function. I
don't believe that's what he meant.

If that wasn't the source of the confusion, what exactly did you mean
by your "Really?" above? You seemed to be questioning Robert's
statements, which were perfectly correct.

To summarize:

You cannot determine the size of a function in (unextended) C.

You can determine the size of a function pointer; this is not relevant
to the size of the function itself.

Applying the sizeof operator to a function name is a constraint
violation. The function name is not implicitly converted to a pointer
as it is in most other contexts.

(gcc, as an extension, yields a meaningless value of 1 when the sizeof
operator is applied to a function name. This is a side effect of its
(arguably ill-advised) support of pointer arithmetic on function
pointers. This is entireliy non-standard, though gcc is permitted to
do this as long as it issues a diagnostic in conforming mode.)

I don't recall seeing any statements in this thread that contradict
any of this.
 
T

Tim Rentsch

Joe Wright said:
We agree that the sizeof a pointer is whatever the size of a pointer is.
My point is that the size of a function is not available. The compiler
cannot know it.

Mostly I've been just skimming the articles in this thread.
However, I had a humorous thought. (Incidentally, it goes
along nicely with Joe's comment, so I'm putting it here.)
Consider "the usual idiom" applied in this discussion:

int
main( void ){
int (*p)(void);

/* get space for 10 functions */
p = malloc( 10 * sizeof *p );

return 0;
}

Needless to say, the code here is nonsensical as C is now.
The sizeof operator doesn't give the size of a variable; it
gives the size of a type -- either the type that is the
operand, or the type of the operand expression. The "size"
of the code that makes up a function can't be determined
based on its type.

So don't any of y'all be a askin for sizeof to work with
function types. :)
 
J

Joe Wright

Keith said:
Joe Wright said:
Keith said:
Robert Gamble wrote:

[...]


Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.
Robert Gamble


Really? Given 'int foo(int);' somewhere the compiler will see 'foo' as
the address of a function. There is no information anywhere as to how
many bytes of memory are required to house foo().

Yes, really, you can apply sizeof to a function pointer. The result
is the size of the pointer, not the size of the function.
Note that "sizeof foo" won't do this, since the argument to sizeof is
one of the contexts in which a function name is *not* implicitly
converted to a pointer.
For example:
#include <stdio.h>
int foo(int i)
{
}
int main(void)
{
int (*foo_ptr)(int) = foo;
printf("sizeof foo_ptr = %d\n", (int)sizeof foo_ptr);
return 0;
}
On one implementation I tried, this prints
sizeof foo_ptr = 4
On another, it prints
sizeof foo_ptr = 8

#include <stdio.h>

int foo(void) {
return 0;
}

int main(void)
{
printf("sizeof foo is %d bytes.\n", (int)sizeof foo);
printf("sizeof printf is %d bytes.\n", (int)sizeof printf);
return 0;
}

At my house, gcc 3.1 prints 1 in both cases.


Yes, I get the same result. With "-pedantic", I also get:

tmp.c:9: warning: invalid application of `sizeof' to a function type
tmp.c:10: warning: invalid application of `sizeof' to a function type

We agree that the sizeof a pointer is whatever the size of a pointer
is. My point is that the size of a function is not available. The
compiler cannot know it.


Right, none of this is in dispute.

Looking at the quoted text above, Robert Gamble wrote:

Just to clarify: you *can* use sizeof on a function pointer, just not
on the function itself.

You replied:

Really?
[...]

And I replied:

Yes, really, you can apply sizeof to a function pointer.
[...]

Perhaps you thought that Robert Gamble was saying that applying sizeof
to a function pointer would give you the size of the function. I
don't believe that's what he meant.

If that wasn't the source of the confusion, what exactly did you mean
by your "Really?" above? You seemed to be questioning Robert's
statements, which were perfectly correct.

To summarize:

You cannot determine the size of a function in (unextended) C.

You can determine the size of a function pointer; this is not relevant
to the size of the function itself.

Applying the sizeof operator to a function name is a constraint
violation. The function name is not implicitly converted to a pointer
as it is in most other contexts.

(gcc, as an extension, yields a meaningless value of 1 when the sizeof
operator is applied to a function name. This is a side effect of its
(arguably ill-advised) support of pointer arithmetic on function
pointers. This is entireliy non-standard, though gcc is permitted to
do this as long as it issues a diagnostic in conforming mode.)

I don't recall seeing any statements in this thread that contradict
any of this.
You're quite right. I don't know how I got it turned around but I
thought it was being argued that 'sizeof main' would give something
useful. Sorry for adding only noise.
 
P

pete

Keith said:
Eric Sosman said:
Robert Gamble wrote:
maadhuu wrote:

i don't think there is anything wrong in knowing such things , not
necessary that it should be always used somewhere,
Agreed, if you don't ask you might never know.

also why is it a violation ??
Because the Standard says so.

Robert's answer is correct, but unsatisfactory. The
obvious follow-up is "But *why* does the Standard say so?" [snip]

Second, the very notion of "the size" of a function is
rather slippery. What if the function has been expanded in-
in five or six places? Is "the size" the total size of all
expansions? If so, it might not be a compile-time constant
if the function is inlined in different translation units.
If "the size" is the memory footprint of one expansion, which
one is it? Note that different in-line expansions may well
generate different instruction counts. What if the optimizer
intermixes the in-line expansion's instructions with those of
the caller? What if the optimizer produces some instructions
that are not strictly attributable to either the caller or
to the expanded function? What if some optimizations occur
at run-time (think "JIT compiler"), using profiling data
gathered during the run, data that might vary from one run
to the next?

If it were useful to compute the size of a function, these particular
issues could be solved. We can take the address of a function, after
all. Even if the function is inlined, perhaps multiple times, the
address gives you something through which the function can be called
with arbitrary arguments.

Having said that, the other reasons why the size of a function is not
useful are perfectly valid.

The size of a function is truly meaningless
under the current rules of C.
Functions are not required to be composed of contiguous bytes,
like objects. Functions may share commmon parts.

Should sizeof yield a big number or a small number,
to describe a Standard Library function
which only consisted of a few instructions,
but which called functions
which consisted of a large number of instructions?
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top