Using extern in a header file

If I declare a function in a header file for use in other modules is it redundant to use the keyword extern?

Header file1:

extern void func1(void);

Source file1:

void func1() {
...do something
}

Source file2:

#include "header1.h"

func1();

It is not redundant - it is simply wrong. You tell the compiler the function will be defined in some other module, then you go ahead an define it anyway.

Regards,
Ray L.

RayLivingston:
It is not redundant - it is simply wrong. You tell the compiler the function will be defined in some other module, then you go ahead an define it anyway.

Regards,
Ray L.

I don't see that. The file that contains the function declaration/implementation does not include the header file with the extern keyword. The file that calls the function does include the header file with the extern keyword, and that's a good thing.

RayLivingston:
It is not redundant - it is simply wrong.

No, using the extern keyword is redundant. The default linkage for this declaration is "extern", which simply means "globally visible" (to the linker). This is independent of whether it appears in the same compilation unit (i.e., file).

You would use the static keyword to indicate that the function should not be visible outside of this compilation unit (i.e., local to this file, not to be linked to other references in other files).

I prefer to use extern in header files, because it helps the reader understand that it is "elsewhere", not "here".

As stated, ‘extern’ is not required for functions as they are global by default. You just need the prototype. You do need the ‘extern’ to share global variables between files.

As also stated, ‘static’ will make the global variable / function private to the file where it’s defined.

And, I believe you can / should #include the .h file with the global declarations both in the file where they are defined and all files that need to use them:

Main Program:

#include "Arduino.h"
#include "Library.h"
void setup()
{
 uint16_t variable = 8;
 Serial.begin(115200);

 variable = addOne(variable);
 Serial.println(variable);
 Serial.println(globalVariable);
}

void loop()
{}

Library.h

#ifndef LIBRARY_H_
#define LIBRARY_H_

#include <stdint.h>

uint16_t addOne(uint16_t);
extern uint16_t globalVariable;

#endif /* LIBRARY_H_ */

Library.cpp:

#include "Library.h"

uint16_t globalVariable;

uint16_t addOne(uint16_t i) {
 globalVariable = i * 7;
 return i + 1;
}

Using "extern" internally only makes sense if you would want to "relay" a declaration from a header to a source in order to avoid complete recompilation of large code bases whenever a declaration changes. Or if you would not want constants (or whatever) to be included multiple times in the code.

Example 1:

//Header
const char message[] = "This message is really great!";

void greatMate();

//Source
void greatMate()
{
  whatever();
}

If you have a program, where the above header is included multiple times, the contents of "message" will also be included in the code multiple times. The following code will only include the contents of "message" once:

Example 2:

//Header
extern const char message[];

void greatMate();

//Source
const char message[] = "This message is really great!";

void greatMate()
{
  whatever();
}

In the last example, you could change the contents of "message" whithout having to re-compile all the sources / objects that includes the header.

gfvalvo:
As stated, ‘extern’ is not required for functions as they are global by default. You just need the prototype. You do need the ‘extern’ to share global variables between files.

That is sometimes true only in Arduino-land, but it is NOT true in normal c/c++ that does not do all the magic mungeing and merging of files the Arduino IDE does. The whole point of extern is to tell the compiler "I'm going to use this function here, but it is defined somewhere else, and that "somewhere else" will be defined at link time. Without it, you would get compile errors, because the compiler would be unable to find the definition of the function. In Arduino-land, .ino files do not require extern, as they are all concatenated into a single source file by the IDE and compiled. But functions defined in other separately compiled c/c++ files are NOT global. By default, the have only file scope. And files that are compiled and then stored in actual library files (NOT the Arduino definition of library) are known only at link-time.
Regards,
Ray L.

RayLivingston:
That is sometimes true only in Arduino-land, but it is NOT true in normal c/c++ that does not do all the magic mungeing and merging of files the Arduino IDE does. The whole point of extern is to tell the compiler "I'm going to use this function here, but it is defined somewhere

I respectfully disagree. The code I posted in in Reply #4 compiles fine using Eclipse / Sloeber. That IDE doesn't include many of the Arduino crutches - i.e. you have to supply function prototypes and even #include "Arduino.h".

I maintain that having the function prototype is sufficient and 'extern' is not required. The linker will find it.

This is not true for variables where 'extern' is required.

The only textbook I have on-hand right now is K&R, Second Edition. Its examples bear out my assertion.

I'll check another text when I get a chance.

But functions defined in other separately compiled c/c++ files are NOT global.

No.

You are confusing file scope with linkage scope. Unless you use "static" on the declaration, it will have global linkage scope. The "extern" attribute is the default linkage (i.e, in the absence of static or extern).

If any identifier (static or extern) is used before it is declared, that will generate an error, but that's a file scope compilation error, remedied by a forward declaration (with or without static or extern). This is not a linkage error.