неопределенные ссылочные ошибки в C ++ - PullRequest
2 голосов
/ 23 мая 2010

У меня есть файлы 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;

    }

}

Ответы [ 3 ]

3 голосов
/ 23 мая 2010

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

3 голосов
/ 23 мая 2010

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

0 голосов
/ 23 мая 2010

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

...