Multiple definition of String-array?

I have this in a header file as a quickFix for getting enum definition texts:

enum enumState {STOP, HOT, PUMP}; 
String enmText[3] = {"STOP", "HOT", "PUMP"};     // index 0..2 !!!!!

In my main sketch I use it this way - more places in the code;

      lcdShow("(" +String(activePump->getPin()) + ") status: " + enmText[activePump->getEnmState()],          
              "Temp.: " + String(activePump->getTemperature()));

when compiling I get this message:

C:\Users\kelds\AppData\Local\Temp\arduino_build_993036\sketch\KS_AirPump_V6.ino.cpp.o (symbol from plugin): In function `enmText':
(.text+0x0): multiple definition of `enmText'
C:\Users\kelds\AppData\Local\Temp\arduino_build_993036\sketch\AirPump.cpp.o (symbol from plugin):(.text+0x0): first defined here
C:\Users\kelds\AppData\Local\Temp\arduino_build_993036\sketch\TempSensor.cpp.o (symbol from plugin): In function `enmText':
(.text+0x0): multiple definition of `enmText'
C:\Users\kelds\AppData\Local\Temp\arduino_build_993036\sketch\AirPump.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

I can't figure out what the problem is - please tell me !

The problem is in the missing code.

Vote number 2, the problem is in your missing code.

Come one, you surely know better than to post snippets of code like that. Post a small but complete sketch that illustrates the problem

You define enmText in a header file, that is obviously included in different .cpp files. So you define it in every .cpp, and the linker complains about multiple definition.
You must define your enmText only once in one of your .cpp files, and declare it external in the header file.

You cannot define variables in header files, only declare them.
(Unless you're using C++17 or newer, where you can mark variables inline and have them defined in the header.)

// header.hpp
#pragma once
extern const char *const enmText[3]; // declaration
// implementaton.cpp
#include "header.hpp"
const char *const enmText[3] { // definition
  "STOP", "HOT", "PUMP",
};

Don't use the String class, especially if the strings don't change. Make constants read-only using the const keyword.
Global enums should not have generic enumerator names like STOP that are bound to clash with libraries and other code. Either use a scoped enum (enum class), or move the enum inside of a class or namespace.
Using arrays of strings to convert enumerators to their names is fragile. It only works for contiguous enums, and the compiler doesn't warn you if you add an enumerator without adding a corresponding string.

I'd recommend using a switch statement:

enum class PumpState { STOP, HOT, PUMP, };

const __FlashStringHelper *to_string(PumpState s) {
  switch (s) {
    case PumpState::STOP: return F("STOP");
    case PumpState::HOT : return F("HOT");
    case PumpState::PUMP: return F("PUMP");
  }
  return F("<invalid>");
}

This also makes it easier to store the strings in Flash rather than RAM. You can overload the to_string function for all enums in your project.

I'd be happier with "You should not..."

1 Like

You can't define a global variable in a header file if the header file is going to be included in more than one source file. Doing that creates multiple definitions of the global variable. Pick one source file for the definition and put an extern reference in the header:

enum enumState {STOP, HOT, PUMP}; 
extern String enmText[3];
#define enmTextContents {"STOP", "HOT", "PUMP"}

Then define the global in one source file:

String enmText[3] = enmTextContents; 

It's way too sophisticated for that minor job ... getting the text !

But THX anyway ...

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