2010-05-23 2 views
2

У меня есть файлы Record.h и Record.cpp. Когда я просто включаю файл Record.h, я получаю несколько неопределенных ссылочных ошибок для функций, определенных в этих файлах. Когда я также включаю Record.cpp, ошибки исчезают. Почему это? Record.h имеет передовые декларации для функций, которые он говорит, является неопределенной ссылкой.неопределенные ссылочные ошибки в C++

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; 

    } 

} 
+1

Показать код ... :-) – paxdiablo

+0

Какой компилятор? – msandiford

+0

Я использую g ++, и он работает нормально. – neuromancer

ответ

0

Мой C++ может быть немного ржавый, но это звучит как Record.cpp не компилируется в раствор. Если файл .cpp не существует, то заголовок ничего не содержит , ссылаясь на. Не включайте cpp, но проверьте настройки компоновщика или команду, которую вы используете для компиляции вашей программы ... она должна включать все cpps.

+0

fyi, sbi сказал, что я пытался ... но более четко. – mpen

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 в рабочем исполняемом файле.

+0

'void foo();' является _declaration_. «Форвард» не имеет смысла, другого нет. Это 'main.cpp', что компилируется отлично, а не' main.o'. Если вы исправите их, мне будет лучше по поводу моего голосования. – sbi

+0

@sbi: Поскольку 'void foo();' является объявлением того, что еще не определено (что касается основной), это по определению является прямым объявлением - есть ли другие, не имеет значения. На самом деле это компиляция g ++ (или, может быть, Phenom), и я слышал как исходный файл (main.cpp), так и файл объекта (main.o), используемый в качестве объекта эргативной формы глагола. Я был для ясности, но, будучи грамматическим нацистом, я был бы рад услышать аргументированный аргумент для одного над другим. – Beta

+0

@Beta, декларации, которые являются или не являются декларациями _forward_: Каков соответствующий практический случай объявления __not__ как объявление _forward_? (Зачем объявлять то, что уже определено, когда по определению определение также является объявлением?) Что касается компилятора: моя посудомоечная машина моет грязные блюда и производит чистые. Аналогично, мой компилятор компилирует исходные файлы и создает объектные файлы. – sbi

3

Обеспечение деклараций, включив в заголовок является то, что компилятор потребности. Компонент нуждается в определениях . Он найдет их в объектных файлах, которые создает компилятор при компиляции исходных файлов.
Я не использую gcc, но я думаю, что его можно просто вызвать со всеми исходными файлами, а затем вызовет компоновщик со всеми предоставленными объектными файлами: g++ main.cpp record.cpp.

Смежные вопросы