Redefinition of type error on static const variable (C vs C++ question?)

photon
Tags: #<Tag:0x00007fe23cc52da0>

#1

I’m working on a Particle Photon Internet Button project, and I can’t seem to get my code to compile. I have the following code that’s more or less what I want which does compille…

static void hello_world(){ Serial.println("Hello, World!"); }

typedef struct DFA_Node DFA_Node_t;
typedef struct DFA_Node{
  bool accepting;
  void (*handler)(void);
  const DFA_Node_t *(*next_node)(char next);
} DFA_Node_t;

#define ESC (0x1B)
#define ACCEPTING_UNIMPLEMENTED_DFA {.accepting = true, .handler = NULL, .next_node = NULL}

extern const DFA_Node_t e;
extern const DFA_Node_t eb;
extern const DFA_Node_t ebA;
const DFA_Node_t *e_f (char next) {return (next == '[' ? &eb  : (next == ESC ? &e : NULL));}
const DFA_Node_t *eb_f(char next) {return (next == 'A' ? &ebA : (next == ESC ? &e : NULL));}
const DFA_Node_t e =   {.accepting = false, .handler = NULL,         .next_node = &e_f};
const DFA_Node_t eb =  {.accepting = false, .handler = NULL,         .next_node = &eb_f};
const DFA_Node_t ebA = {.accepting = true,  .handler = &hello_world, .next_node = NULL};

… but I want all of these to be static as in the following…

static void hello_world(){ Serial.println("Hello, World!"); }

typedef struct DFA_Node DFA_Node_t;
typedef struct DFA_Node{
  bool accepting;
  void (*handler)(void);
  const DFA_Node_t *(*next_node)(char next);
} DFA_Node_t;

#define ESC (0x1B)
#define ACCEPTING_UNIMPLEMENTED_DFA {.accepting = true, .handler = NULL, .next_node = NULL}

static const DFA_Node_t e;
static const DFA_Node_t eb;
static const DFA_Node_t ebA;
static const DFA_Node_t *e_f (char next) {return (next == '[' ? &eb  : (next == ESC ? &e : NULL));}
static const DFA_Node_t *eb_f(char next) {return (next == 'A' ? &ebA : (next == ESC ? &e : NULL));}
static const DFA_Node_t e =   {.accepting = false, .handler = NULL,         .next_node = &e_f};
static const DFA_Node_t eb =  {.accepting = false, .handler = NULL,         .next_node = &eb_f};
static const DFA_Node_t ebA = {.accepting = true,  .handler = &hello_world, .next_node = NULL};

… but I get the following errors:

uninitialized const ‘e’
uninitialized const ‘eb’
uninitialized const ‘ebA’
redefinition of ‘const DFA_Node_t e’
redefinition of ‘const DFA_Node_t eb’
redefinition of ‘const DFA_Node_t ebA’

I know I had done something similar in the past so I tried compiling locally… I realized locally I’m compiling with gcc and from the Particle Desktop IDE, it’s compiling as C++. I tried compiling with g++ locally and got similar errors… So this seems to just be a C vs C++ question? I’m a little more used to C at this point, so maybe there’s a more straight forward way to do this with C++. After some googling around I got rid of the first 3 errors by adding the following struct constructors:

  DFA_Node():accepting(false), handler(NULL), next_node(NULL){};
  DFA_Node(bool accepting, void(*handler)(void), const DFA_Node_t *(*next_node)(char next)): accepting(accepting), handler(handler), next_node(next_node){};

But I’m still getting the redefinition errors.

Any help would be appreciated.

Thanks!
Nathan


#2

Why are you doing it this way?
Why not go with forward declarations for your two functions and only defining your variables once?

Something along this line

// function prototypes/forward declaration
static const DFA_Node_t *e_f (char next);
static const DFA_Node_t *eb_f(char next);

// single variable definition including initialisation
static const DFA_Node_t e =   {.accepting = false, .handler = NULL,         .next_node = &e_f};
static const DFA_Node_t eb =  {.accepting = false, .handler = NULL,         .next_node = &eb_f};
static const DFA_Node_t ebA = {.accepting = true,  .handler = &hello_world, .next_node = NULL};

// function implementation
static const DFA_Node_t *e_f (char next) {return (next == '[' ? &eb  : (next == ESC ? &e : NULL));}
static const DFA_Node_t *eb_f(char next) {return (next == 'A' ? &ebA : (next == ESC ? &e : NULL));}

#3

Oh. Wow. Haha. Yep, that definitely works.

So the main reason I was doing it this way is that it was was closer to how I originally had a my struct setup…

Out of curiosity, how would I resolve trying to do the following?

typedef struct Node Node_t;
typedef struct Node{
  const Node_t *next_node;
} Node_t;

static const Node_t b;
static const Node_t a = {.next_node = &b};
static const Node_t b = {.next_node = &a};

This compiles just fine in C, but I get the same type errors as discussed before in C++. Is there no way to do this in C++?


#4

I don’t quite get why you’d do that :wink:
What does it need to be static or const?
Wouldn’t the way how the items are linked either suggest the ralation should be dynamic or if not dynamic better fit an entirely different construct?


#5

At this point, your first response is what I’m looking for, the follow on question was more academic and syntactically based instead of semantic. I perhaps reduced my example a bit too much for the semantics to make much sense. Originally, I had an array of next nodes, and at compile time wanted the graph of next nodes to be non-dynamic as well as specified with static & const. Is there no way to do this in C++ then? It seems odd to me that C would allow this, but C++ would cripple the ability to do this, so I’m under the assumption that this isn’t the case. I just don’t know how to syntactically enter this in for a C++ compiler to get the same result.


#6

Yup, IIRC C++ only allows forward declaration of variables (which is what you need here) via the extern keyword which implies global linkage scope and hence explicitly contradicts static which implies local linkage.