I have two .cpp files and one .h file in my current project, here's the source:
main.cpp
1 | /*********************** |
2 | * Basic Map Editor * |
3 | * Kelly Crawford * |
4 | * 2 April 2007 * |
5 | ***********************/ |
6 | |
7 | #include <allegro.h> |
8 | extern "C" { |
9 | #include <agup.h> |
10 | } |
11 | #include "dialog.h" |
12 | |
13 | |
14 | |
15 | int main() |
16 | { |
17 | // initialize allegro |
18 | allegro_init(); |
19 | set_color_depth(16); |
20 | set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); |
21 | install_keyboard(); |
22 | install_mouse(); |
23 | |
24 | agup_init(abeos_theme); // initialize agup |
25 | |
26 | do_dialog(the_dialog, -1); // start dialog |
27 | agup_shutdown(); // release dialog |
28 | return 0; |
29 | } |
30 | END_OF_MAIN() |
menu.cpp
1 | /********************** |
2 | * Main Menu Source * |
3 | * Kelly Crawford * |
4 | * 4 April 2007 * |
5 | **********************/ |
6 | |
7 | #include <allegro.h> |
8 | extern "C"{ |
9 | #include <agup.h> |
10 | } |
11 | #include "dialog.h" |
12 | |
13 | int NewMap() |
14 | { |
15 | the_dialog[2].flags = D_GOTFOCUS; |
16 | } |
dialog.h
1 | |
2 | #ifndef DIALOG_INF_H |
3 | #define DIALOG_INF_H |
4 | |
5 | int NewMap(); |
6 | |
7 | MENU file_child[] = |
8 | { |
9 | /* (text) (proc) (child) (flags) (dp) */ |
10 | { "&New", NewMap, NULL, 0, NULL }, |
11 | { "&Load", NULL, NULL, 0, NULL }, |
12 | { "&Save", NULL, NULL, 0, NULL }, |
13 | { "", NULL, NULL, 0, NULL }, |
14 | { "&Quit", NULL, NULL, 0, NULL } |
15 | }; |
16 | |
17 | MENU edit_child[] = |
18 | { |
19 | /* (text) (proc) (child) (flags) (dp) */ |
20 | { "&Resize", NULL, NULL, 0, NULL }, |
21 | { "&Tileset", NULL, NULL, 0, NULL }, |
22 | { "&Name", NULL, NULL, 0, NULL } |
23 | }; |
24 | |
25 | MENU about_child[] = |
26 | { |
27 | /* (text) (proc) (child) (flags) (dp) */ |
28 | { "&About", NULL, NULL, 0, NULL }, |
29 | { "&Help", NULL, NULL, 0, NULL } |
30 | }; |
31 | |
32 | MENU main_menu[] = |
33 | { |
34 | /* (text) (proc) (child) (flags) (dp) */ |
35 | { "&File", NULL, file_child, 0, NULL }, |
36 | { "&Edit", NULL, edit_child, 0, NULL }, |
37 | { "&About", NULL, about_child, 0, NULL } |
38 | }; |
39 | |
40 | DIALOG the_dialog[] = |
41 | { |
42 | /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ |
43 | |
44 | { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, |
45 | |
46 | { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL }, |
47 | |
48 | { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL }, |
49 | |
50 | { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } |
51 | }; |
52 | |
53 | #endif |
It SHOULD compile right, right? Except I'm getting errors that say all of the menus and the_dialog are being declared multiple times. Shouldn't the lines:
#ifndef DIALOG_INF_H #define DIALOG_INF_H
prevent this?
all of the menus and the_dialog are being declared multiple times.
They have to be declared in a .cpp file. Include guards can guard against some things, but not this.
How do I do that, though?
Now I have:
dialog.h
and the dialog.cpp file:
1 | /************************ |
2 | * Dialog and Menu Src * |
3 | * Kelly Crawford * |
4 | * 4 April 2007 * |
5 | ************************/ |
6 | |
7 | #include "dialog.h" |
8 | |
9 | file_child[] = |
10 | { |
11 | /* (text) (proc) (child) (flags) (dp) */ |
12 | { "&New", NewMap, NULL, 0, NULL }, |
13 | { "&Load", NULL, NULL, 0, NULL }, |
14 | { "&Save", NULL, NULL, 0, NULL }, |
15 | { "", NULL, NULL, 0, NULL }, |
16 | { "&Quit", NULL, NULL, 0, NULL } |
17 | }; |
18 | |
19 | edit_child[] = |
20 | { |
21 | /* (text) (proc) (child) (flags) (dp) */ |
22 | { "&Resize", NULL, NULL, 0, NULL }, |
23 | { "&Tileset", NULL, NULL, 0, NULL }, |
24 | { "&Name", NULL, NULL, 0, NULL } |
25 | }; |
26 | |
27 | about_child[] = |
28 | { |
29 | /* (text) (proc) (child) (flags) (dp) */ |
30 | { "&About", NULL, NULL, 0, NULL }, |
31 | { "&Help", NULL, NULL, 0, NULL } |
32 | }; |
33 | |
34 | main_menu[] = |
35 | { |
36 | /* (text) (proc) (child) (flags) (dp) */ |
37 | { "&File", NULL, file_child, 0, NULL }, |
38 | { "&Edit", NULL, edit_child, 0, NULL }, |
39 | { "&About", NULL, about_child, 0, NULL } |
40 | }; |
41 | |
42 | the_dialog[] = |
43 | { |
44 | /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ |
45 | |
46 | { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, |
47 | |
48 | { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL }, |
49 | |
50 | { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL }, |
51 | |
52 | { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } |
53 | }; |
The other two .cpp files (menu.cpp and main.cpp) are unmodified, but I still get the same errors.
The declaration is made in one of the .cpp files, and all the others include the .h file that has the extern definitions.
extern MENU file_child[5]; // incorrect
extern MENU edit_child[3]; // incorrect
extern MENU file_child[]; // correct
extern MENU edit_child[]; // correct
The former is perfectly correct (as is the latter). Putting the values like that even helps the compiler, in some situations.
That said, you generally don't put the size of the array in MENU or DIALOG arrays, since they're NULL terminated anyway, it makes increasing or decreasing the size easier, and the benefits aren't too useful when dealing with them. There's nothing wrong with it of course, it's just not something I see done.
The former is perfectly correct (as is the latter). Putting the values like that even helps the compiler, in some situations.
Oh? I thought it counted as a multiple declaration if more than one file includes that header?
Not as long as it's declared extern. Putting in the array size just lets the compiler know how big the array is (without it, things like sizeof(file_child) won't work).
I wrote about this about a week ago... Read up!
I'm still a little bit confused, as I've never used extern before. I get it, but it's still not working.
main.cpp has remained unchanged.
dialog.h is:
1 | /************************* |
2 | * Dialog + Menu Header * |
3 | * Kelly Crawford * |
4 | * 4 April 2007 * |
5 | *************************/ |
6 | |
7 | #ifndef DIALOG_INF_H |
8 | #define DIALOG_INF_H |
9 | |
10 | #include <allegro.h> |
11 | |
12 | extern int NewMap(); |
13 | |
14 | extern DIALOG the_dialog[]; |
15 | |
16 | extern MENU main_menu[]; |
17 | extern MENU file_child[]; |
18 | extern MENU edit_child[]; |
19 | extern MENU about_child[]; |
20 | |
21 | #endif |
and dialog.cpp is:
1 | /************************ |
2 | * Dialog and Menu Src * |
3 | * Kelly Crawford * |
4 | * 4 April 2007 * |
5 | ************************/ |
6 | |
7 | #include <allegro.h> |
8 | extern "C" { |
9 | #include <agup.h> |
10 | } |
11 | |
12 | #include "dialog.h" |
13 | |
14 | // menu information |
15 | |
16 | MENU main_menu[] = |
17 | { |
18 | /* (text) (proc) (child) (flags) (dp) */ |
19 | { "&File", NULL, file_child, 0, NULL }, |
20 | { "&Edit", NULL, edit_child, 0, NULL }, |
21 | { "&About", NULL, about_child, 0, NULL } |
22 | }; |
23 | //----------------------------------------------------------------------- |
24 | |
25 | MENU file_child[] = |
26 | { |
27 | /* (text) (proc) (child) (flags) (dp) */ |
28 | { "&New", NewMap, NULL, 0, NULL }, |
29 | { "&Load", NULL, NULL, 0, NULL }, |
30 | { "&Save", NULL, NULL, 0, NULL }, |
31 | { "", NULL, NULL, 0, NULL }, |
32 | { "&Quit", NULL, NULL, 0, NULL } |
33 | }; |
34 | //----------------------------------------------------------------------- |
35 | |
36 | MENU edit_child[] = |
37 | { |
38 | /* (text) (proc) (child) (flags) (dp) */ |
39 | { "&Resize", NULL, NULL, 0, NULL }, |
40 | { "&Tileset", NULL, NULL, 0, NULL }, |
41 | { "&Name", NULL, NULL, 0, NULL } |
42 | }; |
43 | //----------------------------------------------------------------------- |
44 | |
45 | MENU about_child[] = |
46 | { |
47 | /* (text) (proc) (child) (flags) (dp) */ |
48 | { "&About", NULL, NULL, 0, NULL }, |
49 | { "&Help", NULL, NULL, 0, NULL } |
50 | }; |
51 | |
52 | //----------------------------------------------------------------------- |
53 | //----------------------------------------------------------------------- |
54 | // Dialog information |
55 | |
56 | DIALOG the_dialog[] = |
57 | { |
58 | /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ |
59 | |
60 | { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, |
61 | |
62 | { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL }, |
63 | |
64 | { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL }, |
65 | |
66 | { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } |
67 | }; |
And yet I am still getting multiple definition errors.
Also, should I include allegro.h and agup.h in all the .cpp files, or just in the dialog.h, since dialog.h is included in all the .cpp files, doesn't that mean allegro is too? Or would it be better form to just include it in all the files it's used in, even if it was already included by dialog.h?
You can include allegro.h and agup.h in as many or as few places as you would like, thats the beauty of headers.
I am still getting multiple definition errors.
I can't see offhand what else is wrong, here are a few comments on stuff though:
extern int NewMap();
Its not really important, but extern is assumed for all function definitions. If you wanted to sound smart in front of C geeks you'd want to drop the explicit usage of the word here.
You also never implement the NewMap function in dialog.cpp, is there reason for this?
Also IIRC your MENU lists should end with a NULL instance, like the dialog does. Aka:
MENU main_menu[] = { /* (text) (proc) (child) (flags) (dp) */ { "&File", NULL, file_child, 0, NULL }, { "&Edit", NULL, edit_child, 0, NULL }, { "&About", NULL, about_child, 0, NULL }, { NULL } };
However, I can't see any multiple definition errors in your code. Could you paste your exact compiler command and the resulting errors. Its important that all this information is copied and pasted exactly (in all its jargony glory).
NewMap() was never implemented because I was going to write the function, but I got all these multiple definition errors and haven't gotten around to it yet. I removed the declaration from my source code for now just for less clutter while we work this out.
So once again, here is all the source + errors:
dialog.h:
1 | /************************* |
2 | * Dialog + Menu Header * |
3 | * Kelly Crawford * |
4 | * 4 April 2007 * |
5 | *************************/ |
6 | |
7 | #ifndef DIALOG_INF_H |
8 | #define DIALOG_INF_H |
9 | |
10 | #include <allegro.h> |
11 | |
12 | extern DIALOG the_dialog[]; |
13 | |
14 | extern MENU main_menu[]; |
15 | extern MENU file_child[]; |
16 | extern MENU edit_child[]; |
17 | extern MENU about_child[]; |
18 | |
19 | #endif |
main.cpp:
1 | /*********************** |
2 | * Basic Map Editor * |
3 | * Kelly Crawford * |
4 | * 2 April 2007 * |
5 | ***********************/ |
6 | |
7 | #include <allegro.h> |
8 | extern "C" { |
9 | #include <agup.h> |
10 | } |
11 | #include "dialog.h" |
12 | |
13 | int main() |
14 | { |
15 | // initialize allegro |
16 | allegro_init(); |
17 | set_color_depth(16); |
18 | set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); |
19 | install_keyboard(); |
20 | install_mouse(); |
21 | |
22 | agup_init(abeos_theme); // initialize agup |
23 | |
24 | do_dialog(the_dialog, -1); // start dialog |
25 | agup_shutdown(); // release dialog |
26 | return 0; |
27 | } |
28 | END_OF_MAIN() |
dialog.cpp:
1 | /************************ |
2 | * Dialog and Menu Src * |
3 | * Kelly Crawford * |
4 | * 4 April 2007 * |
5 | ************************/ |
6 | |
7 | #include <allegro.h> |
8 | extern "C" { |
9 | #include <agup.h> |
10 | } |
11 | |
12 | #include "dialog.h" |
13 | |
14 | // menu information |
15 | |
16 | MENU main_menu[] = |
17 | { |
18 | /* (text) (proc) (child) (flags) (dp) */ |
19 | { "&File", NULL, file_child, 0, NULL }, |
20 | { "&Edit", NULL, edit_child, 0, NULL }, |
21 | { "&About", NULL, about_child, 0, NULL } |
22 | }; |
23 | //----------------------------------------------------------------------- |
24 | |
25 | MENU file_child[] = |
26 | { |
27 | /* (text) (proc) (child) (flags) (dp) */ |
28 | { "&New", NULL, NULL, 0, NULL }, |
29 | { "&Load", NULL, NULL, 0, NULL }, |
30 | { "&Save", NULL, NULL, 0, NULL }, |
31 | { "", NULL, NULL, 0, NULL }, |
32 | { "&Quit", NULL, NULL, 0, NULL } |
33 | }; |
34 | //----------------------------------------------------------------------- |
35 | |
36 | MENU edit_child[] = |
37 | { |
38 | /* (text) (proc) (child) (flags) (dp) */ |
39 | { "&Resize", NULL, NULL, 0, NULL }, |
40 | { "&Tileset", NULL, NULL, 0, NULL }, |
41 | { "&Name", NULL, NULL, 0, NULL } |
42 | }; |
43 | //----------------------------------------------------------------------- |
44 | |
45 | MENU about_child[] = |
46 | { |
47 | /* (text) (proc) (child) (flags) (dp) */ |
48 | { "&About", NULL, NULL, 0, NULL }, |
49 | { "&Help", NULL, NULL, 0, NULL } |
50 | }; |
51 | |
52 | //----------------------------------------------------------------------- |
53 | //----------------------------------------------------------------------- |
54 | // Dialog information |
55 | |
56 | DIALOG the_dialog[] = |
57 | { |
58 | /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ |
59 | |
60 | { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, |
61 | |
62 | { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL }, |
63 | |
64 | { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL }, |
65 | |
66 | { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } |
67 | }; |
And the errors:
multiple definition of `main_menu'
first defined here
multiple definition of `file_child'
first defined here
multiple definition of `edit_child'
first defined here
multiple definition of `about_child'
first defined here
multiple definition of `the_dialog'
first defined here
ld returned 1 exit status
[Build Error] [guistuff.exe] Error 1
Usually, when I double click an error in Dev-Cpp, it highlights the line where the error occurs. Unfortunately it is not taking me to the first definitions.
Unfortunately it is not taking me to the first definitions.
Yes this is because it does not know where they are. Did you do a full recompile?
Also, the compile command itself would be helpful, you can get it by going to the "Compile Log" tab and selecting everything in that textbox.
**
To do a full recompile click this button:
You can also hit control + F11.
** edited in later
I can't believe I didn't rebuild the project. It works now.
Thanks for the help~
Its not really important, but extern is assumed for all function definitions.
assumed for function declarations
If you wanted to sound smart in front of C geeks you'd want to drop the explicit usage of the word here.
declarations
Ah right, I always mix up those two words:P