Help with undefined reference error

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Help with undefined reference error

Post by BroOfTheSun » Fri Dec 12, 2014 2:50 am

Hi, I'm new to the forum, and new to game development. I need some help with an error. I just can't figure out why this is erroring, when I'm including the file that has the function being called. If anyone could help, that would be awesome.

Here's my main:

Code: Select all

...
#include "World/TestLevel.h"

int main()
{
     while(1)
     { 
      while(levelProgression == 1) { Level_TestLevel(); }
     }
     return 0;
}
Here's the TestLevel.h file:

Code: Select all

...
void Level_TestLevel();
...
The compiler is giving me this error message:

Code: Select all

In function 'main':
main.c:(.text+0x16c): undefined reference to 'Level_TestLevel'
make: ...

djcouchycouch
Very interested
Posts: 710
Joined: Sat Feb 18, 2012 2:44 am

Post by djcouchycouch » Fri Dec 12, 2014 3:26 am

Hi there,

Looks like a linker error. It can't find the function defined in the .h file.

Do you have a corresponding World/TestLevel.c file?

Does it contain the implementation of your "void Level_TestLevel()" function?

That's what it seems to be missing.

djcc

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Fri Dec 12, 2014 10:39 am

Hi,

yes, that is a Link-Error.

Can you show us what you pass into your Compiler please? Set up your includes correctly with -I and even using a Makefile you can do that but also set up your VPATH.

Also, and I say this often: NEVER do this in C:

Code: Select all


int main()

Do this:

Code: Select all


int main ( void )

If you are not wishing to pass anything into main then void it. By leaving it open this means that you can pass ANYTHING into your Function - rules are different again for C++ but C allows this and you can pass a large set of Objects into a Function and blow your Stack unwittingly.

Cheers,

Minty.
UMDK Fanboy

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Post by BigEvilCorporation » Fri Dec 12, 2014 11:25 am

MintyTheCat wrote: If you are not wishing to pass anything into main then void it. By leaving it open this means that you can pass ANYTHING into your Function
Wow... you learn something new every day! I've been coding professionally for over 10 years and had no idea this was a thing.

I've been cursing people at work for declaring functions with ( void ) ;) But this is C++11. At least I know where the practice originated from.
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Post by BroOfTheSun » Fri Dec 12, 2014 6:22 pm

There is a "World/TestLevel.c" that has the implementation for "void Level_TestLevel()". Maybe I missed something with how I named that file? It just seems like I missed something small. I'll check that again. Thanks

Also, thanks for the info on using int main( void ). I will make that update. I'm at work atm, and will let you know if I'm able to resolve this issue. Thanks everyone.

I haven't done anything with my compiler, so I may not have setup the includes correctly. I will take a look into this as well.

djcouchycouch
Very interested
Posts: 710
Joined: Sat Feb 18, 2012 2:44 am

Post by djcouchycouch » Fri Dec 12, 2014 6:38 pm

Oh I think I know. The makefile, as is, expects *.c files in a "src" (or maybe "source") folder. Create one and put your .c file in it.

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Fri Dec 12, 2014 6:53 pm

BigEvilCorporation wrote:
MintyTheCat wrote: If you are not wishing to pass anything into main then void it. By leaving it open this means that you can pass ANYTHING into your Function
Wow... you learn something new every day! I've been coding professionally for over 10 years and had no idea this was a thing.

I've been cursing people at work for declaring functions with ( void ) ;) But this is C++11. At least I know where the practice originated from.
....they have found me a nice retirement home just on the outside of Berlin where I can watch the ducks on the river paddle past me as I reminisce the good old days :D

C++ is an abomination, Matt and I am glad I still write in C professionally but C++ has some good points too.
UMDK Fanboy

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Fri Dec 12, 2014 6:55 pm

djcouchycouch wrote:Oh I think I know. The makefile, as is, expects *.c files in a "src" (or maybe "source") folder. Create one and put your .c file in it.
Yes or if you want to use your own includes for data and such just add to the VPATH Variable in the Makefile to include your assets.

Have a look at what the Makefile is set to for its Includes and then pass the correct include directory either by -I or VPATH and you should be alright after that.

Cheers,

Minty.
UMDK Fanboy

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Fri Dec 12, 2014 6:58 pm

BigEvilCorporation wrote:
MintyTheCat wrote: If you are not wishing to pass anything into main then void it. By leaving it open this means that you can pass ANYTHING into your Function
Wow... you learn something new every day! I've been coding professionally for over 10 years and had no idea this was a thing.

I've been cursing people at work for declaring functions with ( void ) ;) But this is C++11. At least I know where the practice originated from.
Yes, even worse check out the Ellipsis - that is pretty much half banned by MISRA these days but how many Functions use it and many are part of the standard CLib such as printf for a start :D

C is pretty bad really but it can work small miracles.
UMDK Fanboy

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Sat Dec 13, 2014 12:04 pm

This got me thinking about Stack usage:

To not take as much Stack space instead of passing many variables in a Function's arguments use a Structure reference:

Code: Select all


void
FuncName ( int a, int b, long c, long d, double e);

Becomes:

Code: Select all


struct t_vars_st
{
   int a;
   int b;
   long c;
   long d;
   double e;
};

..
struct t_vars_st vars;

//Fill in the Variables with values/etc.
..

//Prototype:
void
FuncName ( struct t_vars_st * p_vars );

..
FuncName ( &vars );  //call the Function.
..

Instead of requiring the space to put each Variable instance on the Stack it is only necessary to pass a memory-location which will be say 32 bits so your Stack will benefit in this way.

I actually analyse how much Stack space I use on my MD Programs by filling the Stack with a known value at boot time then I check to see how far down the Stack goes as the program is executed and this helps to determine how much Stack space each given program requires I find.

Cheers,

Minty.
UMDK Fanboy

sega16
Very interested
Posts: 251
Joined: Sat Jan 29, 2011 3:16 pm
Location: U.S.A.

Post by sega16 » Sat Dec 13, 2014 2:56 pm

I am afraid to say that you may not be saving stack space by doing this and using heap for a small struct would be even worse. You see the struct is created on the stack is it not? Unless you declare it as a global variable then it will be at a fixed address, but yet still that uses ram and in fact will always use ram even when unused so therefore I believe it better to use local variables whenever appropriate. Where you will see benefit using a struct is lets take for instance you have a function that used to take a bunch of parameters you need to call it with the same but one parameter as an example. This is more for the benefit of the programmer than performance. This post is more of general advice it would be interesting to compare the generated assembly.

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Sat Dec 13, 2014 10:11 pm

That can be true. However, Stack space versus general memory space allocated to variables is something else. In our MD's case they are both part of Work RAM and we have 68KB of that to use.

There will always be less Stack space as opposed to general memory space so use your Stack wisely:

1. Use recursive Functions sparingly.
2. Do not have lots of multi-level Function calling (usually OOP who come from a Java background are very wasteful when calling Methods and this will not be efficient on the MD).
3. Do some analysis and determine how much Stack space your program is likely to need and do not over allocate the space of blow the Stack either.

However, the Developer can allocate their variables that are going to be used for more than 'scratch' once and not use any Stack space by using the Structure method or even better just have a block with a single reference that the Developer uses as their 'Variable/State Space' and then one would need only to use Offsets from that Reference's Address - used often in DSP and speedy applications for example.

The question to ask: are the Variables long termers such as being members for Game-State or Sprite coordinates, etc or are they something that would be more transitionary? If they are long termers then one does not need to use Stack space as would be used for short-termers.

I think the main thrust is to AVOID at all costs to be wasteful with resources.

The 'generated Assembly' is not relevant to this argument - we are discussing resource usage splitting it between short term and long term variables.

Does that make sense, Sega16?
UMDK Fanboy

sega16
Very interested
Posts: 251
Joined: Sat Jan 29, 2011 3:16 pm
Location: U.S.A.

Post by sega16 » Sun Dec 14, 2014 1:24 am

Yes it does. I did not think of if you called another function (or the same function) in that function with the same parameters.

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Sun Dec 14, 2014 11:36 am

sega16 wrote:Yes it does. I did not think of if you called another function (or the same function) in that function with the same parameters.
Yes, a Function called recursively allocates the same set of temporary variables for each call. Apart from searching and sorting I do not see recursion used that often though.

As a general rule OOP and strict OOD is heavy on the stack as you tend to find lots of Set/Get Methods to modify and access variables within a Class. However, this is wasteful. But it makes perfect sense when one considers encapsulation as it enforces interfaces - something which C does not.

However, we can always sidestep the Stack issue by inlining a Function if we are prepared to pay the codesize penalty that is.
UMDK Fanboy

BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Post by BroOfTheSun » Mon Dec 15, 2014 1:15 am

So I updated my makefile to include my header and source file locations. The Makefile was already setup, but I wasn't placing my files in the right folders. It seems to be finding my files now, and I'm just working through issues in the code.

I've also been reading the comments here, and learning a lot just from the discussion going on here. I will most likely have to go through my code and make updates to optimize memory usage, sometime in the future. Thanks all.

Post Reply