8

Today I encountered a weird problem when trying to use IRremote library, and I managed to strip down the problem as following. If you have a folder in libraries, with Foo.h and Foo.cpp inside, and write a sketch to include Foo.h:

Foo.h

#ifndef Foo_H
#define Foo_H

int AAA() {
    return 0;
}

#endif

Foo.cpp

#include "Foo.h"

Sketch

#include <Foo.h>

void setup(){

}

void loop(){

}

The error message is:

 Foo\Foo.cpp.o: In function `AAA()':

 E:\workShop\Arduino\libraries\Foo\/Foo.h:5: multiple definition of `AAA()'

 includeTest.cpp.o:E:\workShop\Arduino\libraries\Foo/Foo.h:5:

 first defined here

I'm using a Windows 7 32-bit machine. Tested on Arduino 1.0.5, 1.0.4, and 21, 22.


So with some research I figured out the problem comes from my confusion of preprocessor and linking. This question explains how preprocessor includes file and include guard:

These are some of the pages helped me understand linking:

And this is a better explanation of inline specifier:

Community
  • 1
  • 1
Xun Yang
  • 4,209
  • 8
  • 39
  • 68

4 Answers4

13

Well, you have defined the function in two places: once in Foo.cpp where it includes the header, and again in your sketch where it includes the header. C and C++ headers don't provide a module system, they're just literally pasted in place of the include statement.

Either declare AAA in the header, but define it in Foo.cpp (so there's only one definition), or mark it inline.

Useless
  • 64,155
  • 6
  • 88
  • 132
  • 1
    Yeah it works, thanks! I thought `#ifndef Foo_H` was preventing stuff from being defined multiple times. And wasn't inline supposed to be used for improving performance only? – Xun Yang Jun 14 '13 at 11:58
  • @XunYang declaration != definition – juanchopanza Jun 14 '13 at 12:01
  • @XunYang `inline` changes the linkage to cope with functions which are defined in-line. In performance terms, it's really only a hint to modern compilers anyway, so I wouldn't generally consider it an optimization any more. – Useless Jun 14 '13 at 12:34
  • This advice is not the full story. inline keyword has nothing to do with whether the function is defined in a header. inline is a indicator to the compiler that you want it to cut out the function body and insert it into the place where that function is called. inline will cause the function call and return to be eliminated. This saves some execution time for pushing parameters and popping return values, but can increase your code size. Every place a function is called will be replaced with a copy of the entire function code. – jdr5ca Jun 15 '13 at 20:37
  • @jdr5ca , that definitely is not correct any more. It _was_ the case, but compilers are not required to inline function calls just because you use the `inline` keyword, and are perfectly able to inline calls even without it. – Useless Jun 16 '13 at 19:50
6

Well, the distribution of stuff in your files is more than unusual to say the least.

Here is how it is commonly done:

Foo.h

#ifndef Foo_H
#define Foo_H

int AAA(void);  // Just the prototype, not the function body

#endif

Foo.cpp

#include "Foo.h"   // include the h file, although not strictly neecessary

// make the function and body
int AAA(void)
{
    return 0; 
}

Sketch.cpp

#include <Foo.h>  // include prototype, so the AAA function becomes known

void setup()
{
     ...
     AAA();   // call AAA somewhere
}

void loop(){

}
Bbrado
  • 71
  • 4
1

You define the function in the header, so you should use the inline keyword:

inline int AAA(){return 0;}
//               ^^^^^^^^^^ definition

Alternatively, place only the declaration in the header, and the definition in an implementation .cpp file, to be compiled.

Foo.h

#ifndef Foo_H
#define Foo_H

int AAA();

#endif

Foo.cpp

#include "Foo.h"

int AAA(){return 0;}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
0

It is a little more complicated than Bbrado's answer if the structure of your program is a little more complicated. You need to #include <Arduino.h> and #include the help file as shown here:

testCall.ino

#include "testCall.h"
void setup() {
  AAA();
}
void loop() {
}

testCall.cpp

#include "testCall.h"
beeHive AAA(void){
    beeHive a;
    a.bee = (byte)1;
    a.hive = (byte) 2;
    return a;
}

testCall.h

#include <Arduino.h>
struct beeHive {
  byte bee;
  byte hive;
};
beeHive AAA (void); //  prototype only