我有Record.h和Record.cpp文件。当我只包含Record.h文件时,我会在这些文件中定义的函数中获得几个未定义的引用错误。当我还包括Record.cpp时,错误就会消失。这是为什么? Record.h具有函数的前向声明,它声称是未定义的引用。
Record.h
#ifndef RECORD_
#define RECORD_
#include <string>
#include <limits>
using namespace std;
#define PKEYSIZE 10
#define STREETNUMSIZE 8
#define STREETNAMESIZE 24
#define RNAMESIZE 30
#define ASTYLESIZE 20
#define YEARSIZE 12
#define MAXBUCKETSIZE 4
#define MAXDIRECTORYSIZE 100
typedef struct
{
char streetNum[STREETNUMSIZE];
char streetName[STREETNAMESIZE];
char rName[RNAMESIZE];
char aStyle[ASTYLESIZE];
char year[YEARSIZE];
char pkey[PKEYSIZE];
} RECORD;
typedef struct
{
int size;
int depth;
RECORD record[MAXBUCKETSIZE];
} BUCKET;
#define HEADERSIZE 2L
#define NODESIZE sizeof(BUCKET)
void addKey(RECORD *rec_ptr, string key);
void addStreetNum(RECORD *rec_ptr, string s);
void addStreetName(RECORD *rec_ptr, string s);
void addRName(RECORD *rec_ptr, string s);
void addAStyle(RECORD *rec_ptr, string s);
void addYear(RECORD *rec_ptr, string s);
void printRecord(RECORD *rec_ptr);
ostream & operator<<(ostream & out, RECORD *r);
string cvt_binary(unsigned int input);
void addRecord(RECORD *r);
void showbucket(int n);
#endif
Record.cpp
int dirDepth = 0;
int numberOfBuckets = 0;
int directory[MAXDIRECTORYSIZE];
BUCKET bucket[MAXDIRECTORYSIZE/MAXBUCKETSIZE];
void addKey(RECORD *rec_ptr, string key)
{
strncpy(rec_ptr->pkey, key.c_str(), PKEYSIZE);
}
void addStreetNum(RECORD *rec_ptr, string s)
{
strncpy(rec_ptr->streetNum, s.c_str(), STREETNUMSIZE);
}
void addStreetName(RECORD *rec_ptr, string s)
{
strncpy(rec_ptr->streetName, s.c_str(), STREETNAMESIZE);
}
void addRName(RECORD *rec_ptr, string s)
{
strncpy(rec_ptr->rName, s.c_str(), RNAMESIZE);
}
void addAStyle(RECORD *rec_ptr, string s)
{
strncpy(rec_ptr->aStyle, s.c_str(), ASTYLESIZE);
}
void addYear(RECORD *rec_ptr, string s)
{
strncpy(rec_ptr->year, s.c_str(), YEARSIZE);
}
void printRecord(RECORD *rec_ptr)
{
cout<< "|"
<< rec_ptr->pkey << "|"
<< rec_ptr->streetNum << "|"
<< rec_ptr->streetName << "|"
<< rec_ptr->rName << "|"
<< rec_ptr->aStyle << "|"
<< rec_ptr->year << endl;
}
ostream & operator<<(ostream & out, RECORD *r)
{
out << r->pkey << r->streetNum << r->streetName << r->rName
<< r->aStyle << r->year << endl;
return out;
}
int bucketread(short rrn, BUCKET *page_ptr)
{
// long lseek(), addr;
long addr;
addr = (long)rrn * (long)NODESIZE + HEADERSIZE;
lseek(btfd, addr, 0);
return ( read(btfd, page_ptr, NODESIZE) );
}
int bucketwrite(short rrn, BUCKET *page_ptr)
{
// long lseek(), addr;
long addr;
addr = (long) rrn * (long) NODESIZE + HEADERSIZE;
lseek(btfd, addr, 0);
return (write(btfd, page_ptr, NODESIZE));
}
void showbucket(int n)
{
cout << "loading bucket " << n << endl;
BUCKET b;
bucketread(n, &b);
cout << "there are " << b.size << " records in the bucket" << endl;
}
string cvt_binary(unsigned int input) {
if(input == 0) return "0"; // trivial case
string result;
for(int i = numeric_limits<unsigned int>::digits - 1; i >= 0; --i) {
if(input & (1 << i))
{
result += "1";
}
else
{
if(!result.empty()) result += "0";
}
}
return result;
}
string hash (char* key)
{
int sum = 0;
int len = strlen(key);
if (len % 2 == 1) len++; // make len even
//for an odd length string, use the trailing 0 as part of key
for (int j = 0; j < len; j +=2)
sum = (sum + 100 * key[j] + key[j+1]) % 19937;
return cvt_binary(sum);
}
void copyrecord(RECORD *dest, RECORD *src)
{
cout << "copying record" << endl;
addKey(dest, src->pkey);
addStreetNum(dest, src->streetNum);
addStreetName(dest, src->streetName);
addRName(dest, src->rName);
addAStyle(dest, src->aStyle);
addYear(dest, src->year);
}
void addToBucket(int n, RECORD *r)
{
cout << "Adding record " << r->pkey << " to bucket " << n << endl;
if (bucket[n].size == MAXBUCKETSIZE)
{
cout << "Bucket " << n << " is full." << endl;
// examine bucket depth and directory depth to determine next action
cout << "Bucket depth: " << bucket[n].depth << endl;
cout << "Directory depth: " << directory[0] << endl;
}
else
{
copyrecord(&bucket[n].record[bucket[n].size],r);
bucket[n].size++;
bucketwrite(1,&bucket[1]);
}
}
string getreverse(string key, int num)
{
if(num==0)
return "";
string newstring;
newstring = key.at(key.length());
newstring+= getreverse(key.substr(0,key.length()-1),num-1);
return newstring;
}
void addRecord(RECORD *r)
{
cout << r->pkey << endl;
string hashvalue = hash(r->pkey);
cout << "hash value is " << hashvalue << endl;
int directoryDepth = directory[0];
if(directoryDepth == 0)
{
directory[1] = 1;
addToBucket(1, r);
}
else
{
// use hashing to figure out which bucket to add to
cout << "The relevant string is" << getreverse(hashvalue, directoryDepth) << endl;
}
}
答案 0 :(得分:3)
Record.h具有这些功能的声明。 Record.cpp具有定义。
//Record.h
void foo(); // This is a forward declaration
到目前为止一切顺利。
//main.cpp
#include "Record.h"
int main()
{
foo();
}
现在main.o会编译得很好。但是,如果您尝试将其链接到工作二进制文件,则会收到void foo()
未定义的投诉。
//Record.cpp
#include "Record.h"
// This is the definition
void foo()
{
// do various things
}
这可以编译成Record.o,然后可以将其与main.o链接到工作的可执行文件中。
答案 1 :(得分:3)
通过包含标题提供 声明 是编译器所需要的。 链接器需要 定义 。它会在编译器编译源文件时在编译器创建的目标文件中找到它们
我没有使用gcc,但我认为可以使用所有源文件调用它,然后使用提供的所有目标文件调用链接器:g++ main.cpp record.cpp
。
答案 2 :(得分:0)
我的C ++可能有点生疏,但听起来Record.cpp
没有被编译到解决方案中。如果.cpp
文件不存在,则标题中没有引用。不要包含cpp,但要检查链接器设置,或者用于编译程序的命令......它需要包含所有cpps。