0

I have a large project (20+ files) but I managed to set up this small example which recreates my problem. Essentially I have one file (A.cpp) including a second file (B.cpp), but that second file needs several of the variables and functions from the first file. Observe:

A.h:

#ifndef _A_H_
#define  _A_H_
static void foo(int _something);
#endif // #ifndef _A_H_

A.cpp:

#include <iostream>
#include "A.h"
#include "B.h"

using namespace std;

static void foo(int _something)
{
   cout << _something << "\n";
}

int main(int argc, char *argv[])
{
   B *b;

   foo ( 123 ); // So we don't get that pesky defined-not-used warning
   b = new B ();
   b->display ( 123 );
}

B.h:

#ifndef _B_H_
#define  _B_H_
#include "A.h"

class B
{
   public:
      B();
      ~B();
      void display ( int x );
};
#endif // #ifndef _B_H_

B.cpp:

#include "B.h"

void B::display ( int x )
{
   foo ( x );
}

And I am compiling it like so, g++ -Wall A.cpp B.cpp -o main but then I get this error:

A.h:3:13: warning: ‘void foo(int)’ used but never defined [enabled by default]
/tmp/ccFwfZa6.o: In function `main':
A.cpp:(.text+0x54): undefined reference to `B::B()'
/tmp/ccM8SNBK.o: In function `B::display(int)':
B.cpp:(.text+0xd): undefined reference to `foo(int)'
collect2: ld returned 1 exit status

I can tell it's a link error, but I can't tell why I am getting that error.

EDIT:

In my original code I am still getting an error, this time it's about the multiple definition of an integer, here is the error I am getting:

B.o:(.bss+0x4): multiple definition of `some_var'
A.o:(.bss+0x4034): first defined here
collect2: error: ld returned 1 exit status
make: *** [main] Error 1

and I am creating the variable some_var like so

A.h:

#ifndef _A_H_
#define  _A_H_
static void foo(int _something);
int some_var;
#endif // #ifndef _A_H_

How is it possible that some_var would get defined more than once when I have those conditional guards?

puk
  • 16,318
  • 29
  • 119
  • 199
  • 1
    See this question - http://stackoverflow.com/questions/10812769/static-function-declared-but-not-defined-in-c - there is no need to declare the function as static when it's global, and doing so restricts its usage to the compilation unit in which it is declared. –  Dec 08 '13 at 22:28
  • Remove static from foo, and define the constructor for class B. – godel9 Dec 08 '13 at 22:30
  • 1
    This isn't the problem, but names that begin with an underscore followed by a capital letter (`_A_H_`, `_B_H_`) are reserved to the implementation. Don't use them. – Pete Becker Dec 08 '13 at 22:38
  • Despite the title, there's nothing circular here. – Pete Becker Dec 08 '13 at 22:40
  • @PeteBecker Good to know, I was following somebody else's convetions – puk Dec 08 '13 at 23:25
  • "I have a large project (20+ files)" -- no, your project is *tiny*. A large(ish) project will have 1000+ files. – Employed Russian Dec 08 '13 at 23:26
  • @PeteBecker Not circular? Are you sure? To me it looks like `A.cpp`-> `B.ccp` -> `A.cpp` – puk Dec 08 '13 at 23:26
  • @EmployedRussian What I meant was "I have a project which I can not exactly cut and paste here" – puk Dec 08 '13 at 23:27
  • @puk - b.cpp includes b.h; b.h includes a.h; a.h includes nothing. a.cpp includes b.h and a.h; again, b.h includes a.h and a.h includes nothing. No circle. – Pete Becker Dec 08 '13 at 23:35
  • @PeteBecker The problem still persists, please see edits – puk Dec 08 '13 at 23:55

3 Answers3

3

You have no B::B() body at all. Add one, and don't forget about destructor.

Also, remove static from foo().

nyrl
  • 769
  • 5
  • 15
  • Yes, I just realized the `B()` part. Removed static and it appears to work. Will test it out on my main code. – puk Dec 08 '13 at 22:33
1

The problem now is that each source file that #includes a.h gets a definition of int some_var;. In general, variables should be declared in headers and defined in one source file. So in your header you need

extern int some_var;

and in one source file (presumably a.cpp)

int some_var;

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • oh, I thought extern was "somewhere else out there in the universe" not "in the source file which will obviously call me". I will try that – puk Dec 09 '13 at 00:02
  • I am such an idiot, obviously, instead of having `extern blablabla` statements in B.h, it makes more sense to have them in A.h – puk Dec 09 '13 at 00:04
  • @puk - extern **is** "somewhere else out there in the universe". If you define it in a.cpp, then in b.cpp the `extern` means that it's defined in some other translation unit; in a.cpp, it means that it's defined later on. – Pete Becker Dec 09 '13 at 00:05
  • OK now things got even weirder, now if I remove those `extern` statements, things magically work regardless...I had a problem, I fixed it, and now it's as if I never had the problem to begin with – puk Dec 09 '13 at 00:07
  • @puk - that's not necessarily weird. If `some_var` isn't used anywhere other than the source file where it's defined, then you don't need an `extern` declaration. – Pete Becker Dec 09 '13 at 00:10
  • WOW that was extremely painful to debug. I will accept this, but I will answer this question as well, in case someone runs into this problem. – puk Dec 09 '13 at 00:13
0

Thanks to Pete Becker I figured out the problem, and it stemmed mostly from a lack of understanding of all things C/C++.

  1. extern statements are not meant to only be used in header files referencing other header files (ie. in "B.h" writing extern int a where a is defined in "A.c") but also in the original header files (in this case "A.h")
  2. I thought, incorrectly, that a definition needed an equals sign (ie. int a = 1) whereas int a is also a definition. I was, thus, defining my variable in "A.h" when I should have been declaring it like so extern int a in "A.h".
  3. After fixing the above 2, I kept getting undefined reference to a (I literally thought the compiler and linker were taking the piss). I was searching for int a=... in "A.cpp" and as clear as day it was being defined. Turns out this definition was inside a function, and therefore was never being defined.
  4. If all else fails, edit your source files in a trivial way (ie. delete a word and type it again) to force a compilation) as I find changing the header files does not always result in full compilations.
Community
  • 1
  • 1
puk
  • 16,318
  • 29
  • 119
  • 199