Home > Software engineering >  Forward declaration issue, two compilers
Forward declaration issue, two compilers

Time:03-18

I've been developing in C using eclipse as my IDE in my virtual machine with ubuntu, I've made some progress and I wanted to test them in the real product which is an embedded system using powerpc.

In order to compile that program for our product I use Code::Blocks in Windows but the compiler is a powerpc version of the gcc.

The same code is giving me an error in the powerpc version that doesn't appear in the ubuntu version.

I have two header files gral.h and module_hand.h as follows:

The gral.h file:

#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_

#include "module_hand.h"

typedef struct PROFILE
{
    module_t  mod;    // this one comes from module_hand.h
    int       var1;   // some other random variables
} profile_t;

#endif /* HEADERS_GRAL_H_ */

The module_hand.h is defined as follows

#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_

#include <stdint.h>

#include "gral.h"

typedef struct PROFILE profile_t;

typedef struct module
{
    char  name[30];       // name of module
    char  rev[30];        // module revision
    char  mfr[30];        // manufacturer
} module_t;

int Mod_Init(profile_t *profile);
/*  some other random functions */

#endif /* HEADERS_MODULE_HAND_H_*/

As you'll see, I don't use the PROFILE struct in the module struct, But I declare it forward to use it in the declaration of the Mod_Init function

This gives me a Error: redefinition of typedef 'profile_t' and error: previous declaration of 'profile_t' was here

If I remove the forward declaration the error is Error: parse error before '*' token where the line number is the line of the function declaration.

My doubt is what am I missing, and why gcc in Ubuntu does compile it with no problem.

CodePudding user response:

Your powerpc compiler is enforcing the C99 rule that

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except for tags as specified in 6.7.2.3.

(C99 6.7/3)

Your Linux compiler is observing the relaxed version of that rule that was introduced in C11:

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:

  • a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
  • tags may be redeclared as specified in 6.7.2.3.

(C11 6.7/3; also C17 6.7/3)

Supposing that the compilation options are the same, the behavior difference surely arises from using different versions of GCC. More recent versions default to more recent versions of the language.

You could try adding -std=gnu11 or -std=c11 to the command-line options (for both targets) to try to get consistency. If your powerpc version of GCC is too old to accept those then you really need to update to a newer version.

Note also, however, that you don't need to have this problem in the first place. Given that module_hand.h includes gral.h, the former has no need whatever to redefine a typedef that the latter already defines.

Moreover, the fact that these two headers each include the other is a strong suggestion that they ought to be combined into one. Multiple-inclusion guards prevent an actual loop, but they are not an adequate solution.

CodePudding user response:

In the gral.h header file, you define profile_t using typedef, then you redefine profile_t with another typedef in module_hand.h. You should just define the struct PROFILE in gral_h and include gral.h in module_hand.h.

gral.h:

#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_

#include "module_hand.h"

typedef struct PROFILE {
    module_t  mod;    // this one comes from module_hand.h
    int       var1;   // some other random variables
} profile_t;

#endif /* HEADERS_GRAL_H_ */:

module_hand.h:

#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_

#include <stdint.h>

typedef struct module
{
    char  name[30];       // name of module
    char  rev[30];        // module revision
    char  mfr[30];        // manufacturer
} module_t;

int Mod_Init(struct PROFILE *profile);
/* some other random functions */

#endif /* HEADERS_MODULE_HAND_H_*/
  • Related