views:

2594

answers:

7

In C I did not notice any effect of the extern keyword used before function declaration. At first I thought that when defining extern int f(); in a single file forces you to implement it outside of the file's scope. However I found out that both:

extern int f();
int f() {return 0;}

and

extern int f() {return 0;}

compile just fine, with no warnings from gcc. I used gcc -Wall -ansi; he wouldn't even accept // comments.

Are there any effects for using extern before function definitions? Or is it just an optional keyword with no side effects for functions.

In the latter case I don't understand why did the standard designers chose to litter the grammar with superfluous keywords.

EDIT: To clarify, I know there's usage for extern in variables, but I'm only asking about extern in functions.

+2  A: 

The extern keyword informs the compiler that the function or variable has external linkage - in other words, that it is visible from files other than the one in which it is defined. In this sense it has the opposite meaning to the static keyword. It is a bit weird to put extern at the time of the definition, since no other files would have visibility of the definition (or it would result in multiple definitions). Normally you put extern in a declaration at some point with external visibility (such as a header file) and put the definition elsewhere.

1800 INFORMATION
+7  A: 

As far as I remember the standard, all function declarations are considered as "extern" by default, so there is no need to specify it explicitly.

That doesn't make this keyword useless since it can also be used with variables (and it that case - it's the only solution to solve linkage problems). But with the functions - yes, it's optional.

Rageous
Then as the standard designer I'll *disallow* using extern with functions, as it just adds noise to the grammar.
Elazar Leibovich
+2  A: 

We have two files, foo.c and bar.c.

Here is foo.c

#include <stdio.h>

volatile unsigned int stop_now = 0;
extern void bar_function(void);

int main(void)
{
  while (1) {
     bar_function();
     stop_now = 1;
  }
  return 0;
}

Now, here is bar.c

#include <stdio.h>

extern volatile unsigned int stop_now;

void bar_function(void)
{
   while (! stop_now) {
      printf("Hello, world!\n");
      sleep(30);
   }
}

As you can see, we have no shared header between foo.c and bar.c , however bar.c needs something declared in foo.c when its linked, and foo.c needs a function from bar.c when its linked.

By using 'extern', you are telling the compiler that whatever follows it will be found (non-static) at link time.

Its very useful if you need to share some global between modules and don't want to put / initialize it in a header.

Technically, every function in a library public header is 'extern', however labeling them as such has very little to no benefit, depending on the compiler. Most compilers can figure that out on their own. As you see, those functions are actually defined somewhere else.

In the above example, main() would print hello world only once, but continue to enter bar_function().

Externs are very useful for things like signal handlers, a mutex that you don't want to put in a header or structure, etc. Most compilers will optimize to ensure that they don't reserve any memory for external objects, since they know they'll be reserving it in the module where the object is defined. However, again, there's little point in specifying it with modern compilers when prototyping public functions.

Hope that helps :)

Tim Post
Your code will compile just fine without the extern before the bar_function.
Elazar Leibovich
@Elazar , look out for broken compilers.
Tim Post
@Elazar, I already noted, prototyping functions as extern is rather useless with modern compilers :)
Tim Post
Try the same code with Turbo C ++ 3.x on a DOS embedded platform.
Tim Post
Elazar Leibovich
If a header declares a function `static` (it can, but very seldom - as in, essentially never - should), then the function in the public header is not 'extern'.
Jonathan Leffler
So 'extern' for functions could be considered syntatic sugar, like the 'auto' keyword for local variables, or the BASIC LET statement?
Arthur Kalliokoski
@Jonathan Leffler - I can't think of a case where a static declaration /prototype would be useful in a header? But yes, that's obvious.
Tim Post
@Tim: Then you've not had the dubious privilege of working with the code I work with. It can happen. Sometimes the header also contains the static function definition. It is ugly, and unnecessary 99.99% of the time (I could be off by an order or two or magnitude, overstating how often it is necessary). It usually occurs when people misunderstand that a header is only needed when other source files will use the information; the header is (ab)used to store declaration information for one source file and no other file is expected to include it. Occasionally, it occurs for more contorted reasons.
Jonathan Leffler
@Jonathan Leffler - Dubious indeed! I've inherited some rather sketchy code before, but I can honestly say I've never seen someone put a static declaration in a header. It sounds like you have a rather fun and interesting job, though :)
Tim Post
+2  A: 

The extern keyword takes on different forms depending on the environment. If a declaration is available, the extern keyword takes the linkage as that specified earlier in the translation unit. In the absence of any such declaration, extern specifies external linkage.

static int g();
extern int g(); /* g has internal linkage */

extern int j(); /* j has tentative external linkage */

extern int h();
static int h(); /* error */

Here are the relevant paragraphs from the C99 draft (n1256):

6.2.2 Linkages of identifiers

[...]

4 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.

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.

dirkgently
Is it the standard, or are you just telling me a typical compiler's behavior? In case of the standard, I'll be glad for a link to the standard. But thanks!
Elazar Leibovich
This is the standard behavior. C99 draft is available here: <http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf>. The actual standard is not free though (the draft is good enough for most purposes).
dirkgently
I just tested it in gcc and it's both "extern int h();static int h() {return 0;}" and "int h();static int h() {return 0;}" are accepted with the same warning. Is it C99 only and not ANSI? Can you refer me to the exact section in the draft, since this doesn't seem to be true for gcc.
Elazar Leibovich
Check again. I tried the same with gcc 4.0.1 and I get an error just where it should be. Try comeau's online compiler or codepad.org as well if you don't have access to other compilers. Read the standard.
dirkgently
Checked at codepad.org see http://codepad.org/EZrxe4UrThere's an error when marked of course. However it also happens when NOT USING EXTERN. So extern have no effect in this case.
Elazar Leibovich
Not using extern means defaults to external linkage.
dirkgently
Thanks for quoting the standard, however if I understand it correctly, the standard says that not writing extern is just the same as writing extern. What you wrote is true, but is also relevant when just declaring a function. It is superfluous for functions then.
Elazar Leibovich
Yes, it is superfluous for function declarations. (I am not sure what your *real* question is. You seem to be flipping from one point to another. )
dirkgently
@dirkgently, My real question is is there any effect for using exetrn with function declaration, and if there's none why is it possible to add extern to a function declaration. And the answer is no, there's no effect, and there was once an effect with not-so-standard compilers.
Elazar Leibovich
+1  A: 

You need to distinguish between two separate concepts: function definition and symbol declaration. "extern" is a linkage modifier, a hint to the compiler about where the symbol referred to afterwards is defined (the hint is, "not here").

If I write

extern int i;

in file scope (outside a function block) in a C file, then you're saying "the variable may be defined elsewhere".

extern int f() {return 0;}

is both a declaration of the function f and a definition of the function f. The definition in this case over-rides the extern.

extern int f();
int f() {return 0;}

is first a declaration, followed by the definition.

Use of extern is wrong if you want to declare and simultaneously define a file scope variable. For example, extern int i = 4; will give an error or warning, depending on the compiler.

Usage of extern is useful if you explicitly want to avoid definition of a variable.

Let me explain:

Let's say the file a.c contains: #include "a.h"

int i = 2;

int f() { i++; return i;}

The file a.h includes: extern int i; int f(void);

and the file b.c contains:

#include <stdio.h>
#include "a.h"

int main(void){
    printf("%d\n", f());
    return 0;
}

The extern in the header is useful, because it tells the compiler during the link phase, "this is a declaration, and not a definition". If I remove the line in a.c which defines a, allocates space for it and assigns a value to it, the program should fail to compile with an undefined reference. This tells the developer that he has referred to a variable, but hasn't yet defined it. If on the other hand, I omit the "extern" keyword, and remove the int i = 4 line, the program still compiles - i will be defined with a default value of 0.

File scope variables are implicitly defined with a default value of 0 or NULL if you do not explicitly assign a value to them - unlike block-scope variables that you declare at the top of a function. The extern keyword avoids this implicit definition, and thus helps avoid mistakes.

For functions, in function declarations, the keyword is indeed redundant. Function declarations do not have an implicit definition.

+1  A: 

Inline functions have special rules about what extern means. (Note that inline functions are a C99 or GNU extension; they weren't in original C.

For non-inline functions, extern is not needed as it is on by default.

Note that the rules for C++ are different. For example, extern "C" is needed on the C++ declaration of C functions that you are going to call from C++, and there are different rules about inline.

user9876
A: 

The reason it has no effect is because at the link-time the linker tries to resolve the extern definition (in your case extern int f()). It doesn't matter if it finds it in the same file or a different file, as long as it is found.

Hope this answers your question.

Umer Mansoor (www.dvrshark.com)

Umer
Then why allowing to add `extern` to any function at all?
Elazar Leibovich