0

I just don't get the problem with this very simple code... I'm despairing.

testLib.h

#ifndef testLib
#define testLib

int mal2(int wert); // works properly
int abc; // throws: multiple definition of `abc'

#endif

testLib.cpp

#include "testLib.h"

int mal2(int wert) {
  return wert*2;
}

main.ino

#include <testLib.h>

int ergebnis = mal2(5);

// int abc; // throws: error: redefinition of 'int abc'
// abc = 1; // throws: error: 'abc' does not name a type

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:

} 

Why is abc multiple defined if I don't use it in main.ino - shouldn't #ifndef prevent exactly that? If it is already multiple defined, why can't I use one of the other two lines then?

Thanks in advance for any light you bring into my darkness...!

alve89
  • 971
  • 1
  • 9
  • 31
  • 1
    Does this answer your question? [When to use extern in C++](https://stackoverflow.com/questions/10422034/when-to-use-extern-in-c) (not really a dupe, but will probably explain the problem and show the solution) => `extern int abc;` – Lukas-T Jul 19 '20 at 19:43
  • 1
    Alright, I got that. So if I declare a variable somewhere else than in the "same place/scope" I need to use `extern`? – alve89 Jul 19 '20 at 19:47
  • "throws" is very misleading, because it suggests an exception. Just quote the full error you get from the [mcve] which you extracted first. – Ulrich Eckhardt Jul 19 '20 at 19:48
  • consider answering your own question and accepting your own answer as well ;) – Hack06 Jul 19 '20 at 19:50
  • @UlrichEckhardt: That's the whole error message: /var/folders/b5/qc8dstcn02v_hyvgxsq4w9vr0000gq/T/arduino_build_453715/libraries/testLib/testLib.cpp.o:(.bss.abc+0x0): multiple definition of `abc' /var/folders/b5/qc8dstcn02v_hyvgxsq4w9vr0000gq/T/arduino_build_453715/sketch/200719_growboxLibTest.ino.cpp.o:(.bss.abc+0x0): first defined here collect2: error: ld returned 1 exit status – alve89 Jul 19 '20 at 19:50
  • `int abc;` is a so-called *tentative definition*. If there's no other definition in the same [*translation unit*](https://en.wikipedia.org/wiki/Translation_unit_(programming)) then that will be the only definition. By putting a definition in a header-file, all source files that includes that header file will have the definition. And C++ only allows a [single definition](https://en.cppreference.com/w/cpp/language/definition) in a program, so it can only be defined in a single translation unit. By using `extern`, you turn the definition into a *declaration*. – Some programmer dude Jul 19 '20 at 19:50
  • @Someprogrammerdude So the `#ifndef` is ignored? – alve89 Jul 19 '20 at 19:51
  • No, but it only prevents multiple inclusions in a single translation unit. Basically, a translation unit is a single source file with all included header files. The C++ compiler doesn't know anything except the single translation unit it currently compiles. It's the responsibility of the linker to link multiple translation units into a single program. – Some programmer dude Jul 19 '20 at 19:53
  • Do you really need a global variable? The rule of thumb is "never use global variables". They are problematic. – Antonio Jul 20 '20 at 09:49
  • @Antonio I'm really thinking of not using globals but programming an Arduino leads to there quite automatically because out of `setup()` you can't initialize all objects out of setup(). – alve89 Jul 20 '20 at 18:50
  • @alve89 In arduino you can change the `main` program and forget about `setup` and `loop`. In this way you are not forced to use global variables. – Antonio Jul 22 '20 at 12:51
  • @Antonio Very interesting, I didn't know. But after some research I'm not sure about doing this because of possible consequences I can't / I don't want to afford. – alve89 Jul 22 '20 at 15:09

1 Answers1

0

well it is pretty obvious, you are defining int abc in both main.ino and testlib.h. they are in the same namespace hence the naming collision

modified the answer. this is what your code looks like right now

int mal2(int wert); // works properly
int abc; // throws: multiple definition of `abc'

int mal2(int wert) {
  return wert*2;
}

int ergebnis = mal2(5);

// int abc; // throws: error: redefinition of 'int abc'
// abc = 1; // throws: error: 'abc' does not name a type

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:

} 
Adrian Costin
  • 418
  • 3
  • 12
  • The solution is to remove the #include –  Jul 19 '20 at 19:57
  • What I basically don't get is: If `#include` just puts the content of the included file where `include` stands and the `.h` file is only included once (because of `#ifndef` -> how can there be multiple definitions? – alve89 Jul 19 '20 at 19:57
  • your code first includes testlib.h which contains int abc, afterwards you define abc again in the main.ino file, under the first commented line. // int abc; // throws: error: redefinition of 'int abc' – Adrian Costin Jul 19 '20 at 20:02
  • you cannot do this, the abc in main.ino needs to be different than the one defined in the testlib.h file, think of it as this, your include copies the entire testlib.h file above the int ergebnis = mal2(5); line – Adrian Costin Jul 19 '20 at 20:03
  • are you trying to use the int abc from the testlib file inside the main.ino file ? – Adrian Costin Jul 19 '20 at 20:03
  • That's exactly what I try to do - a global variable `int abc`. And the `multiple definitions` error occurs when I keep the both commented lines commented. So only one `int abc` (in testLib.h) shows this error. That's what I don't understand. – alve89 Jul 19 '20 at 20:09
  • you need to use extern int abc, so you can define it inside main.ino as stated above, also make sure you did not forget to actually save the changes to the file. if the lines are commented i don't think it would throw a multiple define error – Adrian Costin Jul 19 '20 at 20:10
  • Without `extern` it does throw the error. Really. Double checked. That's the main reason for my confusion... – alve89 Jul 19 '20 at 20:17