Redefinition of structs error

I'm trying to use this FSM implementation but it won't compile under Arduino:

I created a simple sketch that illustrates the error without the complexity of my particular FSM implementation. It compiles fine using gcc on Debian but fails using Arduino. I tried the preprocessor trick as outlined in point 12 of the sticky but no good. Thanks for any help.

Arduino: 1.8.12 (Mac OS X), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

test.cpp:12:14: error: redefinition of 'state a'
 struct state a = {
              ^
sketch/test.cpp:10:14: note: 'state a' previously declared here
 struct state a, b, c;
              ^
test.cpp:17:14: error: redefinition of 'state b'
 struct state b = {
              ^
sketch/test.cpp:10:17: note: 'state b' previously declared here
 struct state a, b, c;
                 ^
test.cpp:22:14: error: redefinition of 'state c'
 struct state c = {
              ^
sketch/test.cpp:10:20: note: 'state c' previously declared here
 struct state a, b, c;
                    ^
exit status 1
redefinition of 'state a'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
#include <Arduino.h>

struct state;

struct state {
   struct state *parentState;
   struct state *entryState;
};

struct state a, b, c;

struct state a = {
  .parentState = NULL,
  .entryState = &b,
};

struct state b = {
  .parentState = &a,
  .entryState = &c,
};

struct state c = {
  .parentState = &b,
  .entryState = NULL,
};

void setup() {
}

void loop() {
}

You are declaring a, b, and c twice!

Yes clearly I am declaring them twice. The question was why can I do this using gcc on Debian and not using Arduino? Thanks.

The problem seems to be circular references.

a references b
b references a and c
c references b

I can't find any way to do it at initialization time. You will probably have to do it at run time.

struct state
{
  struct state *parentState;
  struct state *entryState;
} a, b, c;


void setup()
{
  a.parentState = NULL;
  a.entryState = &b;


  b.parentState = &a;
  b.entryState = &c;


  b.parentState = &b;
  b.entryState = NULL;
}


void loop() {}

Clearly, we can't see your Debian code.

TheMemberFormerlyKnownAsAWOL:
Clearly, we can't see your Debian code.

Sorry I thought is was understood that the "same code" meant replacing loop and setup with main. Any ideas?

#include <stddef.h>

struct state;

struct state {
   struct state *parentState;
   struct state *entryState;
};

struct state a, b, c;

struct state a = {
  .parentState = NULL,
  .entryState = &b,
};

struct state b = {
  .parentState = &a,
  .entryState = &c,
};

struct state c = {
  .parentState = &b,
  .entryState = NULL,
};

int main() {
  return 0;
}

It compiles fine using gcc on Debian

What makes you think that the fact that it compiles in that environment is correct ? As far as I can see you are trying to redefine the structs named a, b and c. Not surprisingly renaming the second a, b, and c structs ax, bx and cx allows the code to compile, even without setup() and loop() as long as main() is there

What versions of gcc are being used in the two environments ?

UKHeliBob:
What makes you think that the fact that it compiles in that environment is correct ? As far as I can see you are trying to redefine the structs named a, b and c. Not surprisingly renaming the second a, b, and c structs ax, bx and cx allows the code to compile, even without setup() and loop() as long as main() is there

What versions of gcc are being used in the two environments ?

Fair point about the correctness. Also, yes I was thinking about the versions as well. In fact maybe the issue is avr-gcc vs gcc? I'm trying assignment at runtime which to a certain extent already works, but I also have deal with a pointer to an array of struct pointers. Working on it. The FSM implementation is more complex than the example I gave.

I just tried to compile it using gcc on Ubuntu 20.04. Same errors. Do you have your compiler on debian ignoring errors?

wildbill:
I just tried to compile it using gcc on Ubuntu 20.04. Same errors. Do you have your compiler on debian ignoring errors?

Not sure but the actual FSM program (not example) runs fine under Debian. Interesting though that you got the errors. I've googled a few similar issues and gotten the impression that this can be common when asking the question why doesn't it run in Arduino. ie tester (you) has errors in both cases whereas poster (me) does not. I would never of thought that you could/would tell a compiler to ignore errors. Warnings yes. Still working on run-time assignment for actual FSM program. Will let you know.

I don't think this is an opaque pointer issue, it's simply a scope issue.

Edit: The opaque pointer reference seems to have disappeared.

UKHeliBob:
What versions of gcc are being used in the two environments ?

Sorry all about the disappearing posts. I was getting a little carried away with possible solutions. I think I have figured it out. Its not so much a gcc version issue per se but rather a C/C++ standard issue. On Debian the file extension is .c so it compiled to some C standard (I suppose) When I changed the extension to .cpp it compiled to some C++ standard (again I suppose) and I got the same errors as in Arduino.

So now what do I do? I want to keep using Arduino and C++. How do I change the standard in Arduino to something that might allow me to do what I want in C++? Assuming any of the C++ standards allow this. Any references to the different standards that would help me understand this and similar issues?

I got my actual FSM program to compile using runtime assignments. But I can't test it as I don't have an Arduino at home. Will pop into the office later and test it. Hamburgers now. This has made me hungry.

wildbill:
I just tried to compile it using gcc on Ubuntu 20.04. Same errors. Do you have your compiler on debian ignoring errors?

Just to be sure (see my last post). Did you use .cpp as the extension or .c? Thanks.

cpp

If you need a feature of C that is not available in C++ just put that part in C. This compiles without error and produces the expected results:

The Sketch:

extern "C" {
#include "test.h"
}


void setup()
{
  Serial.begin(115200);
  while(!Serial){}
  Serial.println();
  Serial.println("Begin...");
  
  struct state *p;


  for (p = &a; p != NULL; p = p->entryState)
  {
    Serial.print(".name=");
    Serial.print(p->name);
    Serial.print(" .parentState=");
    if (p->parentState == NULL)
      Serial.print("NULL");
    else
      Serial.print(p->parentState->name);
    Serial.print("  .entryState = ");
    if (p->entryState == NULL)
      Serial.print("NULL");
    else
      Serial.print(p->entryState->name);
    Serial.println();
  }
}


void loop() {}

test.h:

#pragma once


struct state
{
  char *name;
  struct state *parentState;
  struct state *entryState;
};


extern struct state a, b, c;

test.c:

#include "test.h"


struct state a, b, c;


struct state a =
{
  .name = "A",
  .parentState = 0,
  .entryState = &b,
};


struct state b =
{
  .name = "B",
  .parentState = &a,
  .entryState = &c,
};


struct state c =
{
  .name = "C",
  .parentState = &b,
  .entryState = 0,
};

Output:

Begin...
.name=A .parentState=NULL  .entryState = B
.name=B .parentState=A  .entryState = C
.name=C .parentState=B  .entryState = NULL

johnwasser:
If you need a feature of C that is not available in C++ just put that part in C. This compiles without error and produces the expected results:

Excellent. Thanks so much. I followed the template you provided and my FSM compiled and ran on a Mega using Arduino. There are still a couple of issues but they don't matter so much for now. This proves that the FSM can be further developed using the framework without access to the hardware. Now I can go back to working on the next revision of the control board the FSM will run on. I'll post about the issues after I get the PCB out for production and have time to work on the software again.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.