51

In *.h header files of a C library, should one declare functions

extern void f();

// or only 

void f();
  1. when using only in C
  2. when using from C++.
Martin York
  • 257,169
  • 86
  • 333
  • 562
Cartesius00
  • 23,584
  • 43
  • 124
  • 195

5 Answers5

61

There's [almost] never any need to use the keyword extern when declaring a function, either in C or in C++. In C and in C++ all functions have external linkage by default. The strange habit of declaring functions in header files with extern probably has some historical roots, but it has been completely irrelevant for decades already.

There's one [obscure?] exception from the above in C, which is probably not directly related to what you are asking about: in C language (C99) if in some translation unit a function is defined as inline and also declared as extern (an explicit extern is used) then the inline definition of that function also serves as an external definition. If no declarations with explicit extern are present in the translation unit, then the inline definition is used as "internal" definition only.

P.S. There's such thing as extern "C" in C++, but that is a completely different matter.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 2
    today the `extern` keyword is often used to bind C/C++ code to Java through the JNI, this is a common solution when using C/C++ with Android, for example. – user827992 Jul 29 '12 at 21:05
  • 8
    @user827992: I'm pretty sure you are talking about `extern "C"` and not the `extern` when declaring a function. – Jesse Good Jul 29 '12 at 21:10
26

In header files of a C library, should one declare functions:

extern void f();
// or only
void f();

Issue 1: Semantics

In a C++ program, the functions are declared as functions returning no value and taking no arguments.

In a C program prior to C23, the functions are declared as functions returning no value and taking an indeterminate but not variable-length list of arguments. In C23, the meaning is the same as in C++.

To get the 'no arguments' meaning in C, use one of:

extern void f(void);
void f(void);

The same notation also means the same thing in C++, though for pure C++ code, using void in the argument list is not idiomatic (do not do it in pure C++ code).

Issue 2: Inter-working between C and C++

Tricky, but the normal rule would that you should declare the functions to C++ code as extern "C". To use the same source code for both, you then need to test the __cplusplus macro. You'd normally do something like:

#ifdef __cplusplus
#define EXTERN_C       extern "C"
#define EXTERN_C_BEGIN extern "C" {
#define EXTERN_C_END   }
#else
#define EXTERN_C       /* Nothing */
#define EXTERN_C_BEGIN /* Nothing */
#define EXTERN_C_END   /* Nothing */
#endif

EXTERN_C void f(void);

EXTERN_C_BEGIN
    void f(void);
    int  g(int);
EXTERN_C_END

The options and variations are manifold, but the header can be used by both C and C++.

The macros would normally be defined in one general-purpose header that's used everywhere, and then the particular header would ensure that the general purpose header is included and then use the appropriate form of the macro.

Issue 3: Style

Formally, there is no need for the extern notation before a function declaration. However, I use it in headers to emphasize that it is a declaration of an externally defined function, and for symmetry with those (rare) occasions when there is a global variable declared in the header.

People can, and do, disagree over this; I go with the local rules — but when I'm the rule-maker, the extern is included in a header.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • It was my fault they were missing the ';' I have fixed the question. – Martin York Jul 29 '12 at 20:58
  • 1
    Thanks for the careful edit, @LokiAstari. I see how the question got to be as it was, and your edit to my answer made sense. (I'd made a mild error in the last sentence, which is why it is now last edited by me once more.) – Jonathan Leffler Jul 29 '12 at 21:02
  • 1
    @JonathanLeffler +1 for issue three, I didn't think you had to have extern (except for the extern "C" in C++). (updated) I prefer to omit the extern in headers and use the rule: if it is static it is *not* public, if it isn't static its public. I would say to the OP, one should declare functions void foo(void); but it is best to go with the local rules on this. Also, I agree only define static functions within the .c file, not in the .h file. – Josh Petitt Jul 30 '12 at 00:22
5

For general use declare as

#ifdef __cplusplus
extern "C" {
#endif
  void f(void);
#ifdef __cplusplus
}
#endif

Otherwise, extern is obsolete.

steffen
  • 8,572
  • 11
  • 52
  • 90
  • Maybe you should add that nifty define '#ifdef _CPLUSPLUS' (or whatever your compiler uses to differ between CPP and C-mode). – ATaylor Jul 29 '12 at 20:42
  • now C++11 add new semantic meaning for extern keyword, like `extern template`. – KAlO2 Jan 21 '15 at 04:08
1

The latter is perfectly fine, since it's only a function definition, which tells those, who include this header: 'There's a function with this prototype somewhere around here'

In this context, functions differ clearly from variables, but that's a different matter. Make sure though, that you do not include the function body, unless you declare it 'inline' or as part of a class definition (C++) or as a 'template function' (also C++).

ATaylor
  • 2,598
  • 2
  • 17
  • 25
1

Specifying extern in function prototype has no effect, since it is assumed by default. Whenever a compiler sees a prototype, it assumes a function is defined somewhere else (in the current or another translation unit). This holds for both of the languages.

The following thread has some useful comments in general about extern.

Effects of the extern keyword on C functions

Community
  • 1
  • 1
Maksim Skurydzin
  • 10,301
  • 8
  • 40
  • 53