It is currently Mon Nov 19, 2018 10:53 am

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sat Nov 10, 2018 11:26 am 
Offline

Joined: Sun Dec 24, 2017 10:16 am
Posts: 4
Hello,

I try to develop on SNES with PVSNESLIB and as long as i use a single code file, everything compile correctly.
I would like to organise my code in multiple file but i didn't find a way to compile it.

For example, i have 3 files :

SimpleSprite.h

Code:
#ifndef SIMPLESPRITE_H
#define SIMPLESPRITE_H
   unsigned char test;
   void SimpleSpriteInit();
#endif


Simpleprite.c :

Code:
#include "SimpleSprite.h"

void SimpleSpriteInit()
{
   test = 'a';
}

main.c :

Code:
#include "SimpleSprite.h"

#include <snes.h>

extern char gfxpsrite, gfxpsrite_end;
extern char palsprite, palsprite_end;


int main(void) {
   SimpleSpriteInit(); // ERROR HERE
   consoleInit();
   oamInitGfxSet(&gfxpsrite, (&gfxpsrite_end-&gfxpsrite), &palsprite, (&palsprite_end-&palsprite), 0, 0x0000, OBJ_SIZE32);

   oamSet(0,  100, 100, 3, 0, 0, 0, 0);
   oamSetEx(0, OBJ_SMALL, OBJ_SHOW);
   
   setMode(BG_MODE1,0); bgSetDisable(0); bgSetDisable(1); bgSetDisable(2);
   setScreenOn();
   
   while(1) {
      WaitForVBlank();
   }
   return 0;
}


This code produce an error when SimpleSpriteInit() is called :

SimpleSprite.obj:SimpleSprite.asm:40: FIX_LABELS: Label "test" was defined more than once.
mn test islsl 0 islfl 0


Here is the file of wla that produce it :
https://github.com/optixx/snes-sdk/blob ... nk/write.c

Do you have informations about that and how can i solve it ?

Thanks in advance for you help.


Top
 Profile  
 
PostPosted: Sat Nov 10, 2018 6:08 pm 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2049
Location: Fukuoka, Japan
This is not a wlalink problem but a C problem: you have defined a variable in a header a file and everytime you will include it in another C file, it will try to define a new "test" variable, thus the error "was defined more than once'.

What you should do is define the variable in one C file then if you need to share it, just "extern" it in the file you need to use it. This is what I do in my C project for the nes.


Top
 Profile  
 
PostPosted: Sat Nov 10, 2018 6:44 pm 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 172
Banshaku wrote:
This is not a wlalink problem but a C problem: you have defined a variable in a header a file and everytime you will include it in another C file, it will try to define a new "test" variable, thus the error "was defined more than once'.

What you should do is define the variable in one C file then if you need to share it, just "extern" it in the file you need to use it. This is what I do in my C project for the nes.

Shouldn't their #ifndef strategy prevent this, though?

Code:
#ifndef SIMPLESPRITE_H
#define SIMPLESPRITE_H
   unsigned char test;
   void SimpleSpriteInit();
#endif

The first time this header file is included, it checks if SIMPLESPRITE_H is defined. It's not, so it defines it and then declares test and SimpleSpriteInit().

The second time it's included, it checks if SIMPLESPRITE_H is defined. This time, it is, so everything between #ifndef and #endif is skipped.


Top
 Profile  
 
PostPosted: Sat Nov 10, 2018 7:08 pm 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2049
Location: Fukuoka, Japan
That's a good question, this is what include guards should do and didn't think much that far when answering since it was my reflex that include = multiple declaration ^^;;;

I think you are right and it shouldn't have cause the issue but I don't know if it good practice to define variables in header but I guess if it makes it easier and you don't have to use extern then it could be one way.


Top
 Profile  
 
PostPosted: Sat Nov 10, 2018 7:39 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20786
Location: NE Indiana, USA (NTSC)
I was under the impression that multiple extern declarations of the same thing were allowed, even within one translation unit,* so long as they're identical.


* A translation unit is what you get after the preprocessor has finished handling things like #include and #define.


Top
 Profile  
 
PostPosted: Sat Nov 10, 2018 8:21 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3687
Location: Mountain View, CA
The placement of variables is being done, IMO, incorrectly in that code. I see this attempted quite often in C code, resulting in an absolute mess of include nonsense that makes no sense. I don't think this concept/issue/matter is taught well (either socially or in CS courses), which is why it's prevalent.

You are quite welcome to declare your functions in an .h file (ex. void SimpleSpriteInit();); this can be used as a form of prototyping and is encouraged. Just be careful.

Your variables, however, need to be declared in the .c file where they're used.

If you have use of global variables, such as unsigned char test;, then this variable declaration should be within what you call main.c.

Then, within what you call SimpleSprite.h, you can have extern unsigned char test;. Any other .c file that has #include "SimpleSprite.h" will then be able to access the global variable called test.

You can also safely #include "SimpleSprite.h" in your main.c without worrying about "double declarations" for test or anything of this sort.

If you want to see an example of how to do this, look at my bsdhwmon code. Specifically, look at f_verbose -- see main.c for its declaration, global.h for its extern and the related VERBOSE() macro that uses it, and all other *.c files that use VERBOSE() (the latter is why it needs to be extern). I could have simply written extern int f_verbose; in every .c file that needed it, but I chose to use a kind of "global macro" that any .c program could use, which references that variable, hence the extern. The linker takes care of the rest.

The short version: do not declare global variables in .h files. Declare the variable within your "main" file, then use extern in other places (either .c files, or an .h file that .c files include).

You can declare typedefs, structs, etc. in .h files of this sort with general safety, though you may need to use an #ifndef/#define approach depending on what it is you're defining.


Top
 Profile  
 
PostPosted: Sun Nov 11, 2018 2:03 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2049
Location: Fukuoka, Japan
So I was right to some degree (my gut feeling told me that variables shouldn't be there but I didn't make C in years so I tend to forget things). As for declaring global in main, I wasn't aware of that but when you think about it, it make sense because it's the entry point of the program and any global should be easy to find, thus putting them in that file.

I think I may have done that indirectly without thinking but one of the other "almost" global (i.e. I decided later that it could be used in other modules) was not there. I will refactor my own code a little bit then.

Maybe for the H file, another way to see it is that it define the prototype of what is accessible in the unit (except for inline functions) so definition, like variables, shoudn't be there (does it make sense? ^^;;).


Top
 Profile  
 
PostPosted: Sun Nov 11, 2018 6:16 am 
Offline

Joined: Sun Dec 24, 2017 10:16 am
Posts: 4
Thank you for your explanations, it solve my problems !

Have a nice day !


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: CypherSignal, Nicole and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group