Reputation: 3327
I have three C++ programs
factor.h
#ifndef FACTOR_H
#define FACTOR_H
/**
* Factor an integer n. Prime factors are saved in flist.
* If n is zero, return -1. If n is negative, factor -n.
* If n is 1, return 0 and do not save any primes in flist.
*
*
* @param n the integer we wish to factor
* @param flist an array to hold the prime factors
* @return the number of prime factors
*/
long factor(long n, long* flist);
#endif
factor.cpp
#include "factor.h"
long factor(long n, long* flist) {
// If n is zero, return -1
if (n==0) return -1;
// If n is negative, we change it to |n|
if (n<0) n = -n;
// If n is one, we simply return 0
if (n==1) return 0;
// At this point we know n>1
int idx = 0; // index into flist array
int d = 2; // current divisor
while (n>1) {
while (n%d == 0) {
flist[idx] = d;
++idx;
n /= d;
}
++d;
}
return idx;
}
test_factor.cpp
#include "factor.h"
#include <iostream>
using namespace std;
/**
* A program to test the factor procedure
*/
int main() {
long flist[100]; // place to hold the factors
for (long n=1; n<=100; n++) {
int nfactors = factor(n,flist);
cout << n << "\t";
for (int k=0; k<nfactors; k++) cout << flist[k] << " ";
cout << endl;
}
}
I was able to get this to run by doing
g++ -c factor.cpp -o factor
g++ -o test_factor test_factor.cpp factor
My confusion is in the second line. When I'm creating an executable for test_factor, how come I only have to call the header file in test_factor.cpp ? How does calling factor.h in test_factor.cpp tell the compiler how the factor function is defined? I just don't get how it automatically recognizes the factor object file I pass in contains the definitions of factor. None of this makes sense to me.
Upvotes: 0
Views: 183
Reputation: 1110
The inclusion of the header is only for knowing the prototype or the symbol that is needed for the local file compilation, and not for knowing the definition itself. That is done by combining the object files, in a later part called the Linkage.
During the compilation of a single file, whenever encountering a new symbol (for example, a name of a function), the compiler checks for its deceleration, if it encounters in such, it puts a place-mark (kind of TODO) in that location, stating that the true reference should be added later. As long as you have the declaration in included header, it is fine with the compiler.
When reaching the stage of combining all the files into one source - the***Linkage*** stage of the compilation, the linker (a part of the compiler) is looking for the real locations of the symbols in the program, and puts the locations instead of these place-marks. If you don't include the object file containing the definition of the symbol, you will get a linkage error:
Undefined reference to <symbol>
This means, that the compiler knows the symbol (since you have included the header), but doesn't know the definition. (also common error is having the same function defined more than once: multiple definition of <symbol>
). This is what the line:
g++ -o test_factor test_factor.cpp factor
is doing - compile the file test_factor.cpp
and link it with the object file test_factor
.
Upvotes: 0
Reputation: 91
how come I only have to call the header file in test_factor.cpp ?
Since you are using factor() in the test_factor.cpp only, you need its declaration, which in your case is provided by factor.h.
In your example, you have included factor.h in factor.cpp also. Technically its not needed there. However it is considered as good practice as it allows compiler to check the declaration (factor.h) against actual function definition (factor.cpp), specifically the number of parameters and their types.
How does calling factor.h in test_factor.cpp tell the compiler how the factor function is defined?
Its the job of linker to stitch the object file containing code for factor() function and the main() function.
g++ -c factor.cpp -o factor
This step (g++ -c) compiles factor.cpp to object file named factor
(its not executable)
g++ -o test_factor test_factor.cpp factor
This steps (g++ -o) compiles test_factor.cpp and calls the linker to link object code for main() with factor
generated above into executable test_factor
.
As a trial you may omit factor
from second step. It will throw linker errors.
Upvotes: 1