Library linking problem

McAgnel

Disciple
Guys,

I was going thru a tutorial in C which asked me to
1. declare a fn in the header file
2. define the fn in c file
3. write another file with main and use the function defined in (2)

Code:
[SIZE="2"]
/* [B]employee.h[/B] */

/* addEmployee reads each field from standard
 * input into the next available Employee slot,
 * as in the exercise in the previous section.
 * It returns the index of the Employee
 * just added, or -1 if the array is full */
int addEmployee(void);

/* printEmployee also returns the index of the
 * Employee just printed, or -1 if the index i
 * is invalid */
int printEmployee(int i);

/* Does what it says: */
int numEmployees(void);[/SIZE]

Code:
[SIZE="2"]/* [B]employee.c [/B]*/
#include "employee.h"
#include <stdio.h>
#include <string.h>

#define MAXEMPS 5

struct Employee {
    char last[16];
    char first[11];
    char title[16];
    int salary;
};

static struct Employee emps[MAXEMPS];
static int nemps = 0;

int addEmployee(void) {
    if (nemps == MAXEMPS)
        return -1;
        
    printf("Enter last: "); fflush(stdout);
    gets(emps[nemps].last);
    if (strlen(emps[nemps].last) == 0)
        return -1;
    printf("Enter first: "); fflush(stdout);
    gets(emps[nemps].first);
    printf("Enter title: "); fflush(stdout);
    gets(emps[nemps].title);
    printf("Enter salary: "); fflush(stdout);
    scanf("%d", &emps[nemps].salary);
    getchar();  /* eat newline */
    
    return nemps++;
}

int printEmployee(int i) {
    if (i < 0 || i >= nemps)
        return -1;
    printf("{%s,%s,%s,%d}",
           emps[i].last,
           emps[i].first,
           emps[i].title,
           emps[i].salary);
    return i;
}

int numEmployees(void) {
    return nemps;
}[/SIZE]

Code:
[SIZE="2"]/* [B]lab6.c[/B] */
#include "employee.h"
#include <stdio.h>

int main() {
    int i;
    
    /* Fill Employee array: */
    while (addEmployee() != -1)
        ;
    
    /* Print each Employee: */    
    for (i = 0; i < numEmployees(); ++i) {
        printEmployee(i);
        putchar('\n');
    }
    return 0;
}[/SIZE]

Now if i compile lab6.c with MSDEV, i get the following error.

ttest.obj : error LNK2001: unresolved external symbol _age
Debug/ttest.exe : fatal error LNK1120: 1 unresolved externals

I am able to guess it should be with the library.
In that case we need to check the linking part.
Can someone tell me how to get this working?
 
OK.

What happens is you are compiling just one file, whereas there are two .C files that need to be compiled.

What you have to do is create a new (empty) project (Windows console app) and add all of the above files to it. Then when you compile it, all will work.
 
You can do the same using the command line tools, or a makefile.
Code:
cl lab6.c employee.c

An MSDEV project is only an elegant way of doing things that can be achieved from command line tools just as easily.
 
The thing with cl.exe is that you have to make sure that the vcvars environment is setup properly.

Besides, why confuse him more than he already is.
 
^Because he will probably learn a few things during the course. IMO, learning to use command line is more important than learning IDEs, as it will also help when he migrates to UNIXen.

Emacs and command line are almost enough for me.
 
that is true to some extent, but MS's makefile format leaves something to be desired.

And the number of libraries you have to specify for certain GUI programming can be overwhelming.
 
I agree wit Yamaraj, it certainly does help cos i am actually learning on the nuances which we miss out.

But i still don't get it.

We are just including the header file. which contains the declarations. But how does it link with definitions which we write in the source file? I needed this one guys. Kindly explain with more detail if possible :)
 
OK.

You include the header files, this tells the compiler that such and such functions exist. Therefore it is able to check the C file for correctness and convert it to a .o file.

You need to do this for both files, as both contain code.

Now, the thing is, each file is compiled separately. During compilation stage, one .c file is not aware of the other (though they are aware of included headers).

File 1 uses functions not defined in itself, nor even in the .h file (which merely has declarations). So all references in file 1 to said functions are not fully resolved yet.

It is at this point that the linker (l in cl.exe) takes the .o files, sees that file2.o contains some symbols needed by file1.o and replaces references in file1.o with references to the code in file2.o and creates a single executable after some amount of relocation.

This executable is then loaded (when executed) by a loader that does some more relocation.

That was a very plain and bad explanation, but it is the simplest I could give.

Libraries have a different technology (somewhat) especially when you go to dynamic linking and loading. Won't get into that. If you want to learn that, read up about ELF and GOT, PLT.
 
Appears to be a good article. I will read it myself tomorrow, it has details that I don't know. Mind you, my explanation is not necessarily entirely correct, I went for simplicity rather than accuracy.
 
Back
Top