0

I'm struggling to correctly set up a few structs that I want to be able to use across multiple files. I want to save some settings for my microcontroller that can be manipulated in some structs. A main structs holds some main settings and structs with more specific settings.

I have a settings.h, a a.h, and a b.h. In the settings.h, I have my structs as follows:

#ifndef LT_SETTINGS_H
#define LT_SETTINGS_H

#include "SD_save.h"

struct ASettings {
  IPAddress ip;
  uint16_t port;
  char *user;
  char *password;

};

struct BSettings {
  bool xEnabled;
  bool yEnabled;
  bool zEnabled;
};

struct Settings {
  char *name;
  ASettings a;
  BSettings b;
  bool active;

  bool changed = false;
} settings;

[...]
#endif //LT_SETTINGS_H

In settings.cpp, I want to have methods for saving and loading these settings from an SD card. In a.h, I have methods relevant to A which need parameters from the ASettings. Something similar goes for b.h and the BSettings. I want to be able to manipulate both the ASettings in a.h and the BSettings in b.h.

How do I accomplish this? I've played around with externs, typedefs, the different settings being in the respective header files, but I can't get it to compile.

If this is a stupid idea to begin with and there is a better solution, please let me know. I have the feeling I'm approaching this incorrectly to begin with.


EDIT 1:

So far, I have only included the settings.h in a.h and b.h and I'm getting a lot of multiple definition errors:

libraries/l/a.cpp.o:(.bss.aSettings+0x0): multiple definition of `aSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.aSettings+0x0): first defined here
libraries/l/a.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/a.cpp.o:(.bss.bSettings+0x0): multiple definition of `bSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.bSettings+0x0): first defined here
libraries/l/sensors.cpp.o:(.bss.bSettings+0x0): multiple definition of `bSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.bSettings+0x0): first defined here
libraries/l/sensors.cpp.o:(.bss.aSettings+0x0): multiple definition of `mqttSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.aSettings+0x0): first defined here
libraries/l/sensors.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/settings.cpp.o:(.bss.aSettings+0x0): multiple definition of `aSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.aSettings+0x0): first defined here
libraries/l/settings.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/settings.cpp.o:(.bss.bSettings+0x0): multiple definition of `sensorSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.bSettings+0x0): first defined here
libraries/l/webconf.cpp.o:(.bss.aSettings+0x0): multiple definition of `mqttSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.aSettings+0x0): first defined here
libraries/l/webconf.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/webconf.cpp.o:(.bss.bSettings+0x0): multiple definition of `bSettings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.bSettings+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1

(I also have b.h included in webconf.h)


EDIT 2:

I changed the initial code a little bit, reducing the compiler errors to this:


libraries/l/a.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/sensors.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/settings.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
libraries/l/webconf.cpp.o:(.bss.settings+0x0): multiple definition of `settings'
sketch/sensor_ap_test.ino.cpp.o:(.bss.settings+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1

a.h:

#ifndef LT_MQTT_H
#define LT_MQTT_H

#include "wm_params.h"
#include "settings.h"

#endif //LT_MQTT_H

b.h:

#ifndef LT_SENSORS_H
#define LT_SENSORS_H

#include "wm_params.h"
#include "settings.h"

[...]

#endif // LT_SENSORS_H

wm_params.h:

#ifndef LT_WM_PARAMS_H
#define LT_WM_PARAMS_H

[...]

#endif // LT_WM_PARAMS_H
Lithimlin
  • 542
  • 1
  • 6
  • 24
  • Doesn't simply including both of `a.h` and `b.h` work? Please post a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). If compilation error appears, pasting them will also be helpful. – MikeCAT Aug 24 '20 at 13:34
  • 1
    `but I can't get it to compile.` I suggest that you fix the thing that prevents it from compiling. – eerorika Aug 24 '20 at 13:39
  • Why do you use pointers at all? – molbdnilo Aug 24 '20 at 13:46
  • updated the original post. I hadn't posted the compile errors before since I had so many different ones and wanted to get a gauge on the idea itself at first. @molbdnilo : I might have this wrong, but I did it so it would refer to the correct struct and not create a new instance. – Lithimlin Aug 24 '20 at 13:54
  • Have you included `a.h` in `b.h` and/or vice versa? Or twice somewhere? If so have you set up gards? (check `#pragma once` or [this](https://en.wikipedia.org/wiki/Include_guard)) Also be sure you haven't named two classes with the same name! – startresse Aug 24 '20 at 13:54
  • @startresse I've checked the include guards multiple times now as that's what I suspected as well, but they're all correct. – Lithimlin Aug 24 '20 at 13:55
  • @Lithimlin please, post your include section of all related files and we can help you. According to your edit, it is definetely include guard problem. – zzz Aug 24 '20 at 14:02
  • I've reread your post and I don't quite understand the issue. You have `a.h`, `b.h`, `settings.h` and `settings.cpp` and you want everything to work in your `settings.cpp`, right? Do you also have `a.cpp` and `b.cpp`? Also what are you using to compile (Makefile, etc...) – startresse Aug 24 '20 at 14:03
  • @startresse yes, I also have a `a.cpp` and `b.cpp` where I have the implementation of the methods. Said methods were not included in the post as they are not relevant to the problem directly. They do use the `aSettings` and `bSettings` at times though. I'm using the arduinoIDE as a compiler since this is a program for a microcontroller. – Lithimlin Aug 24 '20 at 14:13
  • @Swordfish oh, pardon me. The toolchain used is the xtensa-esp32-elf which uses the gcc to compile the code. I'm not sure what the exact flags for the gcc are, but I can check for you if you want me to. I didn't expect it to be a compiler problem, but rather a layer 8 problem. – Lithimlin Aug 25 '20 at 07:48

1 Answers1

1

The variable setting is defined multiple times as the header file settings.h is included by multiple cpp files. A variable should be defined in only one cpp file. To declare a variable in header file, you can use extern keyword.

struct Settings {
  char *name;
  ASettings a;
  BSettings b;
  bool active;

  bool changed = false;
};
extern Settings settings;
Jiho Park
  • 51
  • 3
  • You see, this is what I tried initially. With this I got undefined references. Then I double-checked my `b.h` and realized that I need to declare it there again. After that, it worked. – Lithimlin Aug 24 '20 at 14:51
  • Interestingly, if I declare it in my `a.h` as well, I get a `multiple definition`. If I remove my declaration in `b.h`, however, I get and `undefined reference`. – Lithimlin Aug 25 '20 at 07:42
  • I think you have to clarify between declaring and defining. [definition vs declaration](https://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration/1410632?r=SearchResults&s=4|107.1777#1410632) – Jiho Park Aug 26 '20 at 08:15
  • Briefly, `extern Settings settings` is declaration and `Settings settings` is definition. The definition should appear only once in the entire program, and before you use the variable, it should be declared in the source file (or the included header file). – Jiho Park Aug 26 '20 at 08:17
  • So, the headers should not include any definitions. They should include only declarations. – Jiho Park Aug 26 '20 at 08:19
  • Ah, got them mixed up again. Also was confused by the `extern` keyword. I thought it was a definition already. – Lithimlin Aug 26 '20 at 08:25
  • So you said to define it only once. This would be in the `settings.h` I assume? Or am I misinterpreting your comment? – Lithimlin Aug 26 '20 at 08:28
  • So I read through the answer you linked more thoroughly. So my `struct Settings {...}` already is the definition, correct? So if I include my `settings.h`, I already have the definition. I just need to tell the compiler that `settings` is a struct that exists. But if I add an `extern Settings settings` in only the `settings.h` or in all three header files (`settings.h`, `a.h`, and `b.h`), I get an `undefined reference`. – Lithimlin Aug 26 '20 at 08:50
  • If I add a `Settings settings` to both `a.h` and `b.h` (`extern` only in `settings.h`), I get a `multiple definition`, which I understand. If I add the definition only to `a.h`, it works fine, but if I add it only to `b.h`, I get a `multiple definition`. This sounds to me like I messed up the include guards somewhere, but that is not the case. – Lithimlin Aug 26 '20 at 08:57
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220481/discussion-between-lithimlin-and-jiho-park). – Lithimlin Aug 26 '20 at 08:57