Can a static function declaration conflict with a non-static declaration?

G

Guest

Let's say I have two files, myfile.h and myfile.c:

myfile.h:

int myfunction(int x);

myfile.c:

#include "myfile.h"

static int myfunction(char *x)
{
return 0;
}

Does this conform to the C standard? With GCC 4, this generates an
error, because the definitions of myfunction() conflict. I have a
colleague who says this compiles in GCC 3, because the static version
of myfunction() overrides the non-static prototype from the header
file. I believe that GCC 3 is just ignoring the problem, and that it's
technically a bug, but I can't find any documentation that specifically
says that static and non-static declarations of the same function have
to have the same parameters and return type.
 
C

Chris Torek

Let's say I have two files, myfile.h and myfile.c:

myfile.h:

int myfunction(int x);

myfile.c:

#include "myfile.h"

static int myfunction(char *x)
{
return 0;
}

Does this conform to the C standard?

6.1.2.2 Linkages of identifiers
[snippage]
[#7] If, within a translation unit, the same identifier
appears with both internal and external linkage, the
behavior is undefined.

The first declaration, in myfile.h (first because it is #include-d
before the second declaration) does not use the "extern" keyword and
has no previous declaration in scope, so it specifies external linkage
for the identifier "myfunction".

The second declaration, using the "static" keyword, specifies internal
linkage for the identifier "myfunction".

The behavior is undefined.
With GCC 4, this generates an error, because the definitions of
myfunction() conflict.

Allowed, since the behavior is undefined.
I have a colleague who says this compiles in GCC 3, because the
static version of myfunction() overrides the non-static prototype
from the header file.

Also allowed, since the behavior is undefined.

GCC 4's complaint is probably a good idea, since relying on undefined
behavior when "well-defined behavior" is at least as good is unwise.
(Using undefined behavior for positive benefit, in places where
"well-defined behavior" is no good, is another matter entirely.
That is, I would not call it "unwise" to "#include <graphics.h>"
in order to draw graphics on a screen or window. The cost --
behavior undefined by a widespread standard -- is outweighed by
the benefit of being able to do what the code is required to do.
But here there is no benefit from mixing internal and external
linkage, only a cost.)
I believe that GCC 3 is just ignoring the problem, and that it's
technically a bug, but I can't find any documentation that specifically
says that static and non-static declarations of the same function have
to have the same parameters and return type.

Since the behavior is undefined, anything can happen.
 
B

Ben Pfaff

Chris Torek said:
Let's say I have two files, myfile.h and myfile.c:

myfile.h:

int myfunction(int x);

myfile.c:

#include "myfile.h"

static int myfunction(char *x)
{
return 0;
}

Does this conform to the C standard?

6.1.2.2 Linkages of identifiers
[snippage]
[#7] If, within a translation unit, the same identifier
appears with both internal and external linkage, the
behavior is undefined.

The first declaration, in myfile.h (first because it is #include-d
before the second declaration) does not use the "extern" keyword and
has no previous declaration in scope, so it specifies external linkage
for the identifier "myfunction".

The second declaration, using the "static" keyword, specifies internal
linkage for the identifier "myfunction".

The behavior is undefined.

I agree.

However, it may be worth adding that the opposite situation,
shown below, is OK:

static int myfunction(void);
int myfunction(void) {
...
}

This is because there is an explicit exception for this situation
in the Standard:

For an identifier declared with the storage-class specifier
extern in a scope in which a prior declaration of that
identifier is visible,23) if the prior declaration specifies
internal or external linkage, the linkage of the identifier
at the later declaration is the same as the linkage
specified at the prior declaration. If no prior declaration
is visible, or if the prior declaration specifies no
linkage, then the identifier has external linkage.
 
C

Chris Torek

... it may be worth adding that the opposite situation,
shown below, is OK:

static int myfunction(void);
int myfunction(void) {
...
}

This is because there is an explicit exception for this situation
in the Standard:

For an identifier declared with the storage-class specifier
extern in a scope in which a prior declaration of that
identifier is visible,23) if the prior declaration specifies
internal or external linkage, the linkage of the identifier
at the later declaration is the same as the linkage
specified at the prior declaration. If no prior declaration
is visible, or if the prior declaration specifies no
linkage, then the identifier has external linkage.

The exception quoted here is specific to declarations using the
"extern" keyword. So, this means:

static int myfunction(void);
extern int myfunction(void) {
...
}

is OK. So is:

static double d;
extern double d;

In these two cases, the "extern" keyword functions the same as the
"static" keyword, giving the identifier internal linkage.

Omitting the "extern" keyword entirely is even more bizarre:

[#5] If the declaration of an identifier for a function has
no storage-class specifier, its linkage is determined
exactly as if it were declared with the storage-class
specifier extern. If the declaration of an identifier for
an object has file scope and no storage-class specifier, its
linkage is external.

Note the different specifications for functions vs objects. This
means Ben Pfaff's example (a function) is OK: with no storage class
specifier keyword, the function inherits the linkage of the visible
prior declaration (i.e., the "static" one right above it) -- but
my example with "d" above becomes invalid if the "extern" keyword
is removed:

static double d;
double d; /* ERROR */

I have no idea why this particular (apparently entirely gratuitous)
inconsistency exists in the C standards.
 
R

Richard Tobin

Chris Torek said:
Omitting the "extern" keyword entirely is even more bizarre:

[#5] If the declaration of an identifier for a function has
no storage-class specifier, its linkage is determined
exactly as if it were declared with the storage-class
specifier extern. If the declaration of an identifier for
an object has file scope and no storage-class specifier, its
linkage is external.

Note the different specifications for functions vs objects. This
means Ben Pfaff's example (a function) is OK: with no storage class
specifier keyword, the function inherits the linkage of the visible
prior declaration (i.e., the "static" one right above it) -- but
my example with "d" above becomes invalid if the "extern" keyword
is removed:

static double d;
double d; /* ERROR */

I have no idea why this particular (apparently entirely gratuitous)
inconsistency exists in the C standards.

Presumably it's related to the fact that

double d;

is all you need to do to cause a double to exist, but

int myfunction(void);

still leaves you in need of the definition. There's no default
initializer for functions! The only use of a function declaration
without a body is to declare the function's interface, so why require
the user to add a redundant "extern"?

-- Richard
 

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
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top