Issues placing "typedef struct" in header...

Hi,
Having some issues here getting a typedef struct to work. I have been searching for an answer to this for waaay too many hours. :slight_smile:
I have two sketches in my project and one shared header. When I put a typedef struct or typedef enum I get the following:
In file included from a.pde:1:
a.h:1: error: redefinition of 'struct aStruct'
a.h:1: error: previous definition of 'struct aStruct'
a.h:4: error: invalid type in declaration before ';' token
a.h:4: error: conflicting declaration 'typedef int aStruct'
a.h:4: error: 'aStruct' has a previous declaration as 'typedef struct aStruct aStruct'
a.h:9: error: conflicting declaration 'typedef struct bStruct bStruct'
a.h:9: error: 'bStruct' has a previous declaration as 'typedef struct bStruct bStruct'

Thanks in advance for your help - I appreciate it!

The code is reproduce this ridiculously simple:
main sketch:

#include "a.h"

void setup()
{
}

void loop()
{
}

Header file a.h

typedef struct aStruct {
  int a;
  int b;
} aStruct;

typedef struct {
  int a;
  int b;
} bStruct;

and second sketch file "a.pde"

#include "a.h"

void test()
{
}

typedef_issue.zip (511 Bytes)

Are these two tabs of the same project? If so, the IDE joins them together into one single file before compiling, so you are effectively including your header twice.

Tip: Always wrap your headers in single-inclusion structures:

#ifndef _MY_HEADER_H
#define _MY_HEADER_H

// Header code here

#endif

That way, if the header is included twice, or gets included by another header, the second (and subsequent) inclusions will be ignored.

HI,
Yes they are - I attached the whole sketch to the post. I have one project with two pde files.
I just tried it out and it resolved the issue
This is the first time I have split my code into multiple modules so I have not experienced this quirk before. If I understand you right then I only include them once.
If they are concatenated then does that mean that all header contents become global to all modules?
Thanks
Bryon

bryonb:
HI,
Yes they are - I attached the whole sketch to the post. I have one project with two pde files.
I just tried it out and it resolved the issue
This is the first time I have split my code into multiple modules so I have not experienced this quirk before. If I understand you right then I only include them once.
If they are concatenated then does that mean that all header contents become global to all modules?
Thanks
Bryon

Yep. It's done so that you don't have to declare any of your functions / variables as external in order to reference them properly. Makes for lazy programmers, but also means that new programmers don't have to know about sharing variables and functions between C++ files. It does have little trip-ups though :wink:

Separate the typedef from the struct definition.

struct aStruct {
  int a;
  int b;
};

typedef struct aStruct aStruct;

struct bStruct {
  int a;
  int b;
};

typedef struct bStruct bStruct;

Then:

#include "a.h"

aStruct as;
bStruct bs;

void setup()
{
}

void loop()
{
}

Compiles just fine.

Thanks Paul. I tried your suggestion and the same error occurs. If they are concatenated then I can't see how that would work actually.
Either way, I have a solution and I am now painfully aware that it is not straight forward to port from a full C compiler to Arduino. :slight_smile:
Thanks to all for helping resolve this for me. The responses are faster than a paid-for vendor-support contract! :slight_smile:
Bryon

Thanks Paul. I tried your suggestion and the same error occurs.

Then you did something wrong, because I compiled the code before posting it.

If they are concatenated then I can't see how that would work actually.

What is "they" that you think is being concatenated?

I am now painfully aware that it is not straight forward to port from a full C compiler to Arduino.

Only if you don't do it right. The Arduino is programmed in C++, which is a superset of C.

Which version of the Arduino IDE are either of you using?

I used 1.0.4. I think. Might have been 1.0.3.

Why not just dispense with the typedef altogether? It's not necessary and only blurs the fact that you are using a structure for the sole benefit of not having to say struct xxxx yyyy when you want to create one.

typedef struct aStruct {
  int a;
  int b;
} aStruct;

Can you do that? Most of the code I've seen/written has done

typedef struct aStruct_ {
  int a;
  int b;
} aStruct;

to explicitly separate the structure name from the type name. But I'm not sure whether that was mostly a style thing, or an actual namespace requirement. (It's an easy and painless fix...)

The syntax for structs is historically wacky.

struct fred
{ int a;
int b;
}

defines a structure called "struct fred" and you can declare an instance of this struct by

struct fred fred_instance ;

or by

struct fred
{ int a;
  int b;
}  fred_instance ;

On the other hand

typdef struct fred
{ int a;
  int b;
}  another_name_for_fred

defines a struct which has two alternative names, "struct fred" and "another_name_for_fred". So you can declare instances by

struct fred                    instance_a;
another_name_for_fred  instance_b ;

and instance_a and instance_b should be functionally equivalent.

It's confusing.

So what you have done in your example, is used the same identifier for the struct and also for it's typedef alternative name, which is probably confusing. If you want to give something an alternative name, it should probably be a different alternative name. If you were called John, and you said your alternative name was John, well that would be silly.

Or use an anonymous struct:

typedef struct {
  char foo;
  char bar;
} foobar;

Or, don't typedef at all, as (I believe, correct me if I am wrong) C++ does an implicit typedef of all structs anyway.

Of course, we have allowed ourselves to get sidetracked and off topic. This issue wasn't the typedefs themselves, but the fact that the OP had two tabs, and was including the same header file in both, which resulted in a single cpp file with the header included twice when the IDE concatenated the two tabs into one file before attempting to compile.

Now if I looked at your last example there, I would have trouble to figure out if 'foobar' was a typedef name
for that struct, or an instance of it.

I hate writing things which, when I look at it six months later, I can't figure out what it is, so I try
to avoid writing things like that in the first place.

I am still unclear, is

typedef struct fred
{  int a;
   int b;
} fred ;

Actually legal, or not ? Could I then write

struct fred instance_a ;
fred instance_b ;

and expect both to work ?

afremont is on the money, drop the typedef. michinyon shows the main reason why the added confusion is not worth it; by dropping the typedef, your aliased type name suddenly becomes a variable.

aliased structs are only useful in C++ when you actually need something different to what is written before the '{}', such as anonymous structs, i.e

typedef struct{
  int a;
  int b;
} fred, *fredptr;

//Allows aliased names:
fred a;
fredptr b = &a;

Yes 'struct' is legal on variable definitions, however it is only needed to disambiguate names:

int fred( int a ){    //Function named 'fred'
return ~a; 
}

struct fred    //structure named 'fred'
{ int a;
  int b;
};

struct fred a; //Struct required to disambiguate 'fred'