Hi,
Despite triple checking my code for duplication and checking that the headers include #ifndef I still can't trace what is causing this error message:

drawscr.o(.bss+0x0):drawscr.cpp: multiple definition of `massage'
main.o(.bss+0x0):main.cpp: first defined here

Ideally I'd create the pointer at struct definition time via a declarator.

// drawscr.cpp

#include <iostream>
#include <string>
#include "drawscr.h"

using namespace std;

void initMsg() {
/* initMsg(void) 
    return void;

    Generate the stock strings for the fancy formatting

*/
  message->top[0] = '\xC9';
  for (int i=1;i<SCRNSIZE-2;i++) message->top[i] = '\xCD';
  message->top[SCRNSIZE] = '\xBB';

  message->blank[0] = '\xBA';
  for (int i=1;i<SCRNSIZE-2;i++) message->blank[i] = '\f';
  message->blank[SCRNSIZE] = '\xBA';
}
// drawscr.h

#ifndef _DRWSCREEN_H
#define _DRWSCREEN_H
using namespace std;
using std::string;

#define SCREEN Screen
#define CLS 0
#define SCRNSIZE 80

struct Screen {
  int w;
  int h;
  int curX;
  int curY;
};

struct MsgStock {
  char top[SCRNSIZE];
  char blank[SCRNSIZE];
} *message;

// prototypes
void initMsg();
void writeMsg(string);

#endif /* _DRWSCREEN_H */
// main.cpp

#include <iostream>
#include <string>
#include "drawscr.h"

using namespace std;
using std::string;

int main() {

  initMsg();
  cout << message->top;

  return 0;
}

Recommended Answers

All 8 Replies

line 22 in the drawscr.h is causing the problem because that header file is included in both *.cpp files. That line is actually declaring a pointer named message. To correct this remove the declaration of message from line 22 and declare it as extern extern strucvt MsgStock* message; . Then in ONE of the *.cpp files declare it again but this time WITHOUT the extern keyword.

The #include "filename" directive effectively works by directly inserting the named file into the text.

// z.h
int i;
// z.cpp
#include "z.h"
// main.cpp
#include "z.h"

int main() {
  i = 42;
  return 0;
  }

Is the same as:

// z.cpp
int i;
// main.cpp
int i;

int main() {
  i = 42;
  return 0;
  }

So you have, in fact, declared the variable twice.

To get around that, declare it as extern.

// z.h

// declare the variable to exist, but don't cause it to exist
extern int i;
// z.cpp
#include "z.h"  // the variable is only declared as existing

// cause the variable to exist
int i;
// main.cpp
#include "z.h"  // the variable is declared as existing

int main() {
  // the variable is usable here, since main.ccp knows it exists...
  i = 42;
  return 0;
  }

Your code has one other problem. message is declared as a pointer to a thing, but no instance of that thing actually exists. You must either malloc() or statically declare the thing before using it.

Using malloc()

void initMsg() {
  message = malloc( sizeof( MsgStock ) );
  ...

Statically declaring it:

MsgStock _message;  // static variable

void initMsg() {
  message = &_message;  // now 'message' points to something
  ...

Hope this helps.

..snip..
So you have, in fact, declared the variable twice.

To get around that, declare it as extern.

I was sure that was the point of the preprocessor directives #ifndef etc... back to the books for me, I think :-)

Your code has one other problem. message is declared as a pointer to a thing, but no instance of that thing actually exists. You must either malloc() or statically declare the thing before using it.

Using malloc()

void initMsg() {
  message = malloc( sizeof( MsgStock ) );
  ...

Statically declaring it:

MsgStock _message;  // static variable

void initMsg() {
  message = &_message;  // now 'message' points to something
  ...

Hope this helps.

Thanks, it really does. I obviously need to revisit the chapters on pointers as yet again they've blown my mind.

>> was sure that was the point of the preprocessor directives #ifndef etc
Nope, has nothing at all to do with that. Those directives are useful when a header file is include multiple times, which is often the case when including system header files.

// header1.h
#include <stdio.h>
...
<other stuff here>
// main.cpp
#include <header1.h>
#include <stdio.h>
...

Now when the above main.cpp is compiled it includes header1.h and stdio.h. Without the code guard tags that are in stdio.h that would result in tons of errors because of duplicate declarations when main.cpp includes stdio.h.

I know this is probably daft, but wasn't I including the same header file multiple times in drawScr.cpp and main.cpp?

I know this is probably daft, but wasn't I including the same header file multiple times in drawScr.cpp and main.cpp?

No.

The file "drawscr.cpp" includes three files: iostream, string, and drawstr.h. Each file is included but once.

Likewise, the file "main.cpp" includes three files: iostream, string, and drawstr.h. Again, each file is included but once.

"drawscr.cpp" gets compiled to "drawscr.o". And "main.cpp" gets compiled to "main.o". Then the linker puts them together into "a.exe" or "a.out" or whatever.

BTW. In "drawscr.h" you use std::string but never actually include <string>. What if the user (that is, the programmer using your code) didn't include <string> before including "drawscr.h"?

In a like vein, included files should never have using statements in them.

In both these cases, you can get away with it because it is a small project you are working on by yourself, but when things get larger and when other people become involved, invariably you'll wind up breaking someone's (reasonable) assumptions on what is what.

The only difference between daft and obvious is knowledge. Hope you feel less daft now... (and don't put yourself down).

:)

You know it's funny, you've totally spun things I was semi-confident about on their head...
Thanks a million!

But seriously... I need to find some better literature...
My 'beginners guide' is looking pretty shabby in this new light.

I've been putting in 'using namespace std; and using std:string' in every file possible (it seemed to stop those pesky compile time errors from appearing). ;)

I've also been unsure about the whole header file methodology. I thought that just by including a header just meant that the whole header would be inserted into the cpp file, and therefore you wouldn't have to have duplicate include statements in a foo.h & foo.cpp pair.

I realise now I was probably just lucky that things worked out. (not that they always did of course..)

While my programming is currently purely exploratory, I do want to feel like i have 'some' idea as to what is going on. Blatantly, I don't.

But don't worry about my confidence taking a dive, this is the sort of thing to make me work harder! onwards and upwards!

Ah, yes.

The thing to remember is that in C++ there are two parts to everything: the definition of a thing's type and the declaration of a thing itself.

The type of a thing is an abstract concept. As such, it compiles to zero bytes worth of executable code. (Discounting RTTI info and the like, which is something different.) A thing itself, though, is entirely different. It occupies space. So, you can't have an integer, but you can have a specific integer value, like 2 or -7.

Include files are fluff. They don't compile to anything. What they do is inform the compiler about data stored somewhere else. Typically, this is information about the types of things, and fairly often (as in the case with the extern value) information about a specific thing stored elsewhere.

So, main.cpp does actually have the "drawscr.h" header inserted directly in the file (well, maybe not, but that's another issue. For all intents and purposes it is just inserted). All the header should do is tell main.cpp about stuff that exists elsewhere (specifically, in drawscr.cpp, about which main.cpp knows nothing).

So, when main.cpp gets compiled with, say, c++ -c main.cpp you get an object file that contains all the actual things that main.cpp defines. Main.cpp doesn't define message, but it knows about it and can use it, because the drawscr.h include file told the compiler that message exists somewhere else.

Likewise, when drawscr.cpp gets compiled c++ -c drawscr.cpp you get an object file that contains all the actual stuff defined in drawscr.cpp (such as message).

But drawscr.h never gets compiled. It is only information.

Lastly, the linker joins main.o and drawscr.o into a binary file that you can execute directly. If none of the object files actually declare the stuff that the compiler was told exists (say, if drawscr.o didn't declare message), then the linker complains that one or more of the object files is trying to use stuff that doesn't exist anywhere.

Often times you will see stuff like having #include "drawscr.h" in drawscr.cpp. That's fine. In fact (as it is in your case), it is often necessary because the include file, again, informs the compiler about the types of things that drawscr.cpp uses. If you didn't include it, the compiler would choke when you try to declare message and when you try to access message's data, saying "What the heck is 'message'? Is it supposed to point to something? What does that thing look like? I don't know... Fooey!"

Hope this helps.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.