Undefined Reference Problem

Hi all, this is a really wierd problem as I have not come across it before.

Some info before I start:
IDE: CodeBlocks 13.12
OS: Windows 7
Language: plain C

I have two files io.c and io.h.

Im currently working on a function called 'IO_Append_File' in io.c and I wanted to test some of the function before continuing to finish it. It uses a function which I have not written a definition for yet, 'IO_Close_File'. This means it is declared in the io.h file. For some reason, even though I am #include-ing io.h, it spits the error 'undefined reference to 'IO_Close_File'.

Here are the files:

io.c ( errors are at line 81 and 96 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "io.h"
#include "general.h"

void setUpFile ( FILE* fp )
{
	//Go to beginning of file
	fseek ( fp, 0, SEEK_SET );

	//Write for this systems endianness ( 4-byte integer to start of file )
	unsigned int iPut = 1;
	fwrite ( &iPut, sizeof ( int ), 1, fp );

	//Write 0 as a 4-byte integer afterwards ( for error checking )
	iPut = 0;
	fwrite ( &iPut, sizeof ( int ), 1, fp );
}

IO_File* IO_Append_File ( char* fileName, unsigned int sugAlloc )
{
	//Open for reading and writing in binary mode
	int isNew = 0;
	FILE* fp = fopen ( fileName, "rb+" );
	if ( fp == NULL )
	{
		fp = fopen ( fileName, "wb+" );
		isNew = 1;
	}

	if ( fp == NULL )
	{
		printf ( "IO File Error: File Error\n" );
		return NULL;
	}

	//Allocate Struct needed for this
    IO_File* filePtr = malloce ( sizeof ( IO_File ) );
    memset ( filePtr, 0, sizeof ( IO_File ) );

    //Transfer File Pointer
    filePtr->fp = fp;

	//Get endianness of this machine
	int lilEnd = isLittleEndian();

	//If the file is not newly created, read all data into the IO_File struct
	if ( isNew == 0 )
	{
		//Get first 4 bytes as an integer to check endianness of stored file
		//---

		//Read the integer
		unsigned long endianInt = 0;
		fread ( &endianInt, sizeof ( long ), 1, fp );

		//Check to see if fread failed ( cut short ) by reaching end of file
		if ( feof ( fp ) )
		{
			//If so, fix the file ( Set up Endianness and empty int )
			setUpFile ( fp );
		}
		else
		{
			if ( endianInt == 1 )
			{
				//Is the Endianness of this machine
				filePtr->littleEndian = lilEnd;
			}
			else if ( endianInt == 16777216 )
			{
				//Opposite of the endianness of this machine
				filePtr->littleEndian = !lilEnd;
			}
			//Anything else means an error for the file
			else
			{
				//Unload all allocations and file pointers
				printf ( "IO File Error: Endian Incorrect\n" );
				IO_Close_File ( filePtr );
				return NULL;
			}

			//Make sure the second 4 byte integer is empty ( just a simple check )
			//---

			//Load what should be an empty value
			unsigned int emptyVal = 1;
			fread ( &emptyVal, sizeof ( int ), 1, fp );

            //Make sure its an empty value
            if ( emptyVal != 0 )
			{
				printf ( "IO File Error: Empty Value not Empty\n" );
				IO_Close_File ( filePtr );
				return NULL;
			}

			//Load all variables within the files
			//---

			//Count how many variables there are
			//Note: A Null pointer will signify the end of the header
            unsigned int varPtr = 0;
            int varAmount = 0;
            do
			{
				fread ( &varPtr, sizeof ( int ), 1, fp );
				varAmount++;
			} while ( varPtr != 0 && !feof ( fp ) );
			filePtr->varAmount = varAmount;

			//LEFT OFF
            //Allocate the
		}
	}
	//If the file is new, Initialise it
	else
	{
		//Set up the file with Endian indicator and empty Int
		setUpFile ( fp );
	}

	//Initialise Variable array
	filePtr->varAmount = 0;
	filePtr->fileData = NULL;

	return filePtr;
}


io.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#ifndef IO_H_INCLUDED
#define IO_H_INCLUDED

#define IO_DATA_BIG_BLOCK 1
#define IO_INDEX_OUT_OF_RANGE 3

#define FILE_BLOCK_PTR_SIZE sizeof ( int )
#define START_FILE_POS 8

//These many index of IO_File_Data are allocated in advance
//Note: not implemented yet
#define BLOCK_PTR_ALLOC_PADDING 10

typedef struct
{
	//The direct Pointer to the variable in the file
	unsigned int pData;

	//The size of the data
	unsigned int dataSize;
} IO_File_Data;

typedef struct
{
	//Pointer to an array of variable indexes
	IO_File_Data* fileData;

	//Amount of Variables currently in the file ( size of fileData )
	unsigned int varAmount;

	//Pointer to the File
	FILE* fp;

	//The endianness of the file ( is it little endian? )
	int littleEndian;
} IO_File;

//Opens a file for reading and writing
//If the file does not exist, it creates the file and sets it up
//If the file does exist, it reads all the data into memory as variables
//fileName is the path to the file to be opened
//On success, returns a pointer to the struct holding possible data and information on file
//On failure, returns a null pointer
IO_File* IO_Append_File ( char* fileName, unsigned int sugAlloc );

//Frees all dynamic allocations and closes the file pointer
void IO_Close_File ( IO_File* filePtr );

//Writes data to a particular index ( block ) in the file
//Will return error code IO_DATA_BIG_BLOCK if the data size is too big for the block pointer
//If the index is in the centre, I.E. has data behind it and/or data infront of it...
//...Data infront will be pushed forward. This is an expensive operation. ...
//...dataSize should be checked if this operation is not wanted to occur.
int IO_Write_Data ( IO_File* filePtr, int index, char* data, int dataSize );

//Grabs data from a particular index in the file
//This is done by looking at the block pointer at the given index
int IO_Get_Data ( IO_File* filePtr, int index, char* buffer, int bufferSize );

#endif // IO_H_INCLUDED 


Could it be just some silly error that I have not noticed yet?

Many Thanks,
Super_Stinger
> I wanted to test some of the function before continuing to finish it
> It uses a function which I have not written a definition for yet,
¿what do you expect to happen then?
If you try to use a function for which there is no provided definition, you'll get an "you are trying to use a function but you haven't provided a definition for it" error
That's what undefined reference means.
Yes, Yes I know.

I thought that if you declare a function in the .h file, but not provide a definition ( so its still declared ), it will compile fine. Indeed using the function will produce unexpected results, but for testing other parts of the program, i just need it to compile. Do I have to provide a definition as well as the declaration for the compiler to be happy? ( I thought that it did not need to be ).
Last edited on
Hi,

Just provide a minimal stub:

1
2
3
void IO_Close_File ( IO_File* filePtr ) {
    printf ("In the IO_Close_File Function");
}


Or, hell, even try empty braces :+)

Btw, you should make use of the return values from functions, by assigning them to a variable. For example fread returns a size_t value.

Hope my 1 cent worth helped a little
Indeed it has TheIdeasMan, many thanks!

Yep, thats what I do now and it works!
> I thought that if you declare a function in the .h file, but not provide a definition
> it will compile fine.
undefined reference is a linker error, if it reached the linker stage then it did compile fine.


> Just provide a minimal stub:
that may be error prone, the code would build fine and the lack of implementation would be manifested in logic errors.
Topic archived. No new replies allowed.