static keyword

E

eryer

Hi,
i have a question about static function...for example:

file1.c
static void foo(void);
.....
void foo ()
{
...
}

in this example, optimizations due to static keyword at compiler time
are performed or not? Or is more correct do something like:

file1A.c
static void foo(void);
.....
static void foo ()
{
...
}

Thanks
 
I

Ian Collins

eryer said:
Hi,
i have a question about static function...for example:

file1.c
static void foo(void);
.....
void foo ()
{
...
}

in this example, optimizations due to static keyword at compiler time
are performed or not?

Such as? The static keyword simply tells the compiler not to export the
name; it is only visible in the compilation unit where it is declared.
Or is more correct do something like:

file1A.c
static void foo(void);
.....
static void foo ()
{
...
}

It makes no difference.
 
B

BGB / cr88192

eryer said:
Hi,
i have a question about static function...for example:

file1.c
static void foo(void);
.....
void foo ()
{
...
}

in this example, optimizations due to static keyword at compiler time
are performed or not? Or is more correct do something like:

file1A.c
static void foo(void);
.....
static void foo ()
{
...
}

IMO, it is better to have both declarations the same, as in the latter case.

that said, static defines semantics, not optimizations.
static on a function will essentially just hide it from other compilation
units, but typically little more than this.
this is the same semantics as for global variables.


any optimizations done, or not done, due to the use of static are compiler
dependent.
in most cases, there is unlikely to be much of any real difference though...

granted then, if you mean putting a static in a header, vs a non-static
function in another compilation unit, this does effect something: it may
allow the compiler to inline the function (the inline keyword may also serve
as a hint for it to do so as well, although not all compilers accept the
'inline' keyword).

however, in this case, the optimization would be due to the visability of
the function (it being in the same compilation unit, hence the compiler can
see its sourse), and not due to 'static', which in this case would serve
mostly to "hide" the function from other compilation units (such that you
can put the function in a header without risking the linker making a big
fuss and possibly refusing to link the program).

I have observed though that linkers may also silently "merge" all these
duplicate static functions (from headers), such that they don't take up lots
of extra space in the compiled output.

a similar observation is that the compiler may also omit the functions if
they are never called.


but, then again, all this is still due to the semantics, of the modifier,
rather than a result of the modifier itself.

for example, it is very well possible that a compiler will inline a function
even though it does not use any extra keywords, ...

and, it is also very well possible that a compiler will be stupid and not do
anything differently than simply obey the semantics of the keyword (IOW:
avoid a link-time error due to multiple-definition).
 
N

Nobody

i have a question about static function...for example:

file1.c
static void foo(void);
.....
void foo ()
{
...
}

in this example, optimizations due to static keyword at compiler time
are performed or not?

Maybe.

Declaring the function "static" gives the compiler more scope for
optimisation, as it can determine exhaustively the contexts in which the
function may be called.
 
F

Flash Gordon

Nobody said:
Maybe.

Declaring the function "static" gives the compiler more scope for
optimisation, as it can determine exhaustively the contexts in which the
function may be called.

This could allow it to take shortcuts on the calling conventions, it
might also encourage inlining, especially for a function which is ony
called once.
 
S

Stephen Sprunk

Flash said:
This could allow it to take shortcuts on the calling conventions,

Interesting. For instance, a compiler for x86 might decide to forgo the
usual stack-based calling convention and use a register-based one, which
would be faster (assuming the number of arguments is reasonable). It
might also allow the compiler to skip saving some registers in the
calling function if it knows that the called function won't modify them.

However, does any compiler in the wild actually do this?
it might also encourage inlining, especially for a function which is ony
called once.

I suspect that, in general, compilers would either inline or not
regardless of the static designation.

I can see one way the heuristics might be affected, though. If the
called function validates its arguments, and the compiler can prove that
the validation has already been done (or explicit values set) by every
calling function, it may end up with a bunch of dead code that can be
eliminated, which in turn might drop the size below its heuristics'
threshold for inlining.

S
 
E

Eric Sosman

Interesting. For instance, a compiler for x86 might decide to forgo the
usual stack-based calling convention and use a register-based one, which
would be faster (assuming the number of arguments is reasonable). It
might also allow the compiler to skip saving some registers in the
calling function if it knows that the called function won't modify them.

However, does any compiler in the wild actually do this?

Dunno about that specific optimization, but there have
certainly been compilers that optimized `static' functions
differently than externally-linked ones. A <ctype.h> header
I once encountered contained *definitions* of toupper() and
the rest of the functions, all `static'. The accompanying
compiler would discard any that weren't used, and would try
to in-line those that were. This was, oh, fifteen or twenty
years ago, well before `inline' came into the language. (In
fact, the header was for the pre-ANSI VAXC compiler.)

If you formed a function pointer to isdigit(), say, and
passed it somewhere, the compiler would naturally compile a
free-standing (but still `static') isdigit() function. This
raised the possibility that two different translation units
could form isdigit() pointers that would compare unequal. I
don't know whether that possibility would violate anything in
the Standard; there was a discussion maybe twenty-five years
ago about whether `memcpy == memmove' was permissible, and IIRC
no satisfactory conclusion was ever reached.
 
R

Richard Bos

Eric Sosman said:
the Standard; there was a discussion maybe twenty-five years
ago about whether `memcpy == memmove' was permissible, and IIRC
no satisfactory conclusion was ever reached.

I can't see a reason why not.

Behaviour isn't a reason. memmove() has stricter requirements than
memcpy(), but in the cases where they differ, memcpy() has undefined
behaviour. If the outcome of that undefined behaviour happens to be
"behaves as if it were memmove()", that is certainly required.

Address _could_ be a reason, but I cannot find anything in the Standard
which demands that different functions have addresses that compare
differently. Nor, for that matter, can I find an explicit, blanket
demand that all objects' addresses must differ.
The difference between these cases is, of course, that objects can be
assigned to, and functions can be called. If you assign a value to one
object through a pointer, and that changes another object behind your
back, a conforming program will be able to notice. Therefore, assigning
to one object's address must not change what is at another object's; and
therefore, objects' addresses must be distinguishable.
Functions, though, are different. You can't assign to them; you can only
call them. When the only difference between two functions occurs when
there is undefined or implementation-defined behaviour, there is no
guarantee that any strictly conforming program can detect the difference
at all.
There is a parallel, by the way, in a specific type of object: string
literals. No strictly conforming program can assign a value to a string
literal; implementations can, and do, take advantage of this by merging
(partly) equal string literals, making their addresses identical or
making the address of one fall inside the other.

Put most illustratively, I would say that memmove == memcpy is
permissible for the same reason that "bcde" == "abcde"+1 is.

Richard
 
E

Eric Sosman

Eric Sosman said:
the Standard; there was a discussion maybe twenty-five years
ago about whether `memcpy == memmove' was permissible, and IIRC
no satisfactory conclusion was ever reached.

I can't see a reason why not.

Behaviour isn't a reason. memmove() has stricter requirements than
memcpy(), but in the cases where they differ, memcpy() has undefined
behaviour. If the outcome of that undefined behaviour happens to be
"behaves as if it were memmove()", that is certainly required.
[...]

That's the gist of the argument as I recall it. Others
didn't buy it, and the discussion raged back and forth for no
few exchanges before sort of petering out. Early-to-middle
1990's, IIRC, should anyone want to excavate the ruins.
 
L

lawrence.jones

Richard Bos said:
Address _could_ be a reason, but I cannot find anything in the Standard
which demands that different functions have addresses that compare
differently. Nor, for that matter, can I find an explicit, blanket
demand that all objects' addresses must differ.

6.5.9p6:

Two pointers compare equal if and only if both are null
pointers, both are pointers to the same object (including a
pointer to an object and a subobject at its beginning) or
function...

Different objects are not "the same object", nor are different functions
"the same function".
 
N

Nobody

Interesting. For instance, a compiler for x86 might decide to forgo the
usual stack-based calling convention and use a register-based one, which
would be faster (assuming the number of arguments is reasonable). It
might also allow the compiler to skip saving some registers in the
calling function if it knows that the called function won't modify them.

However, does any compiler in the wild actually do this?

Consider the case where the function is inlined more than once, then
common subexpression elimination moves (most of) the inlined code into a
separate subroutine. If the function is static, and all calls have been
inlined, the "real" function definition will be elided.

The effect is the same as implementing the function with a custom calling
convention.
 
F

Flash Gordon

Nobody said:
Consider the case where the function is inlined more than once, then
common subexpression elimination moves (most of) the inlined code into a
separate subroutine. If the function is static, and all calls have been
inlined, the "real" function definition will be elided.

If and only if the function's address is not stored in a pointer (which
applies to my earlier comments too).
The effect is the same as implementing the function with a custom calling
convention.

It can be, but not always.

One reason you might get different (faster) calling conventions is if
there is an API which specifies one set of conventions (for flexibility)
but something else is faster on modern hardware. If the function is
static and no pointers to it exist, then the compiler knows it is safe
to use the faster calling conventions.

A reason a static function might be inlined when a non-static function
is not is that the balance on code size moves. If it is static and no
pointer is taken, then if all calls are inlined and the original
eliminated it has not inflated code size by as much as inlining it *and*
keeping the original. This is especially relevant if the function is
only called a small number of times (the extreme case being a function
called exactly once).

So I always declare and define functions as static unless I explicitly
need them to be externally visible. Always give the compiler all the
information you can, it might help it make the best decision...
 
R

Richard Bos

6.5.9p6:

Two pointers compare equal if and only if both are null
pointers, both are pointers to the same object (including a
pointer to an object and a subobject at its beginning) or
function...

Different objects are not "the same object", nor are different functions
"the same function".

That has not stopped implementation writers from equalising pointers to
string literals. In the source code, these are definitely different
objects, but since a program can only discover the difference by
invoking undefined behaviour, they are allowed to be "the same object"
for pointer purposes. Unless you're telling us that this _very_ common
optimisation is illegal, I don't see why the same thing should not be
allowed for functions for which the same proviso holds.

Richard
 
K

Keith Thompson

That has not stopped implementation writers from equalising pointers to
string literals. In the source code, these are definitely different
objects, but since a program can only discover the difference by
invoking undefined behaviour, they are allowed to be "the same object"
for pointer purposes. Unless you're telling us that this _very_ common
optimisation is illegal, I don't see why the same thing should not be
allowed for functions for which the same proviso holds.

There are no objects in my source code; objects exist only during
program execution.

The object in question is the "array of static storage duration"
mentioned in C99 6.4.5p5. The standard explicitly allows two string
literals to refer to the same object in C99 6.4.5p6:

It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.

As for memcpy and memmove possibly having the same address, I can
imagine a program storing the address of a standard function and later
making some decision based on which standard function the address
points to. I have difficulty imagining *good* code doing something
like this, but it isn't the standard's job to impose good coding
practices.
 

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,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top