I found some code that made me a bit intrigued: there is a header file declaring only structures that are being used in code for an embedded system written in C.
This is an example of code in the header:
#ifdef _structures_h_
extern struct{
uint16_t State_ON;
uint16_t State_OFF;
uint16_t State_HI;
uint16_t Counter;
}Switch;
#endif
#ifndef _structures_h_
#define _structures_h_
struct{
uint16_t State_ON;
uint16_t State_OFF;
uint16_t State_HI;
uint16_t Counter;
}Switch;
#endif
In the source files that make use of those structures, in some of them, the inclusion is done like this:
#define _structures_h_
#include "structures.h"
In others there is just the inclusion of the header file as shown below:
#include "structures.h"
My doubt is, is there some reason for declaring the structures in both ways in the same header file?
Is there any difference or relevant impact in coding declaring the same struct as extern or not in a header filer?
This is the first time that I have found such a situation and I was not able to find a reasonable explanation for using this.
The difference between the two code sections is that, in the first (the one that has the extern
keyword), the structure variable is declared but not defined. That is, the code specifies that the Switch
variable is defined elsewhere (in another translation unit). However, in the second section, the Switch
variable is formally declared and defined – or, at least, tentatively defined; that tentative definition will become an actual definition if/when the compilation of the translation unit completes with no other full definition (i.e., one with an initializer) occurring.
In that second conditional block, the definition of the _structures_h_
token is very strange; and, unless there is more to the header than you have shown, I can really see no purpose for it:
Switch
variable with different types (even though those types have exactly equivalent definitions, they are still separate types); that redefinition is an error.Switch
variable from each of the TUs that include the header without first themselves defining the _structures_h_
token.But I would agree with you and the other answerer that code like this is both confusing and error-prone: For example, using that header in multiple translation units without a preceding _structures_h_
definition will cause multiple definitions of the Switch
variable.
Also, rather than using the #ifndef ...
block, a simple #else
would suffice and make things clearer (IMHO).
Here's a shortened, annotated version of the header:
#ifdef _structures_h_
extern struct {
uint16_t State_ON;
uint16_t State_OFF;
uint16_t State_HI;
uint16_t Counter;
} Switch; // Already defined elsewhere - just need the declaration
#else
struct {
uint16_t State_ON;
uint16_t State_OFF;
uint16_t State_HI;
uint16_t Counter;
} Switch; // Not yet defined, so we provide a "tentative" definition
#endif
Or, an even shorter way, which avoids the multiple specifications of the structure (and the errors that could lead to), is to define a separate 'linkage' macro that is either extern
or nothing:
#ifdef _structures_h_
#define SW_LINKAGE extern
#else
#define SW_LINKAGE /* */
#endif
SW_LINKAGE struct {
uint16_t State_ON;
uint16_t State_OFF;
uint16_t State_HI;
uint16_t Counter;
} Switch;