如何在代码中删除未定义的引用?

时间:2014-12-22 18:07:18

标签: c makefile undefined-reference

我遇到了这个编译错误,我想知道如何调试代码。我的程序基本上有以下文件:

生成文件:

CFLAGS = -Wall -g
src = ex19.c

all: $(src)
    cc $(CFLAGS) -o ex19 $(src)

ex19: object.o

clean:
    rm -f ex19

object.h:

#ifndef _object_h
#define _object_h

typedef enum{
    NORTH, SOUTH, EAST, WEST
} Direction;

typedef struct {
    char *description;
    int (*init)(void *self);
    void (*describe)(void *self);
    void (*destroy)(void *self);
    void *(*move)(void *self, Direction direction);
    int (*attack)(void *self, int damage);
} Object;

int Object_init(void *self);
void Object_destroy(void *self);
void Object_describe(void *self);
void *Object_move(void *self, Direction direction);
int Object_attack(void *self, int damage);
void *Object_new(size_t size, Object proto, char *description);

#define NEW(T, N) Object_new(sizeof(T), T##Proto, N)
#define _(N) proto.N

#endif

object.c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "object.h"
#include <assert.h>

void Object_destroy(void *self) {
    Object *obj = self;

    if(obj) {
        if(obj->description) free(obj->decription);
        free(obj);
    }
}

void Object_describe(void *self) {
    Object *obj = self;
    printf("%s.\n", obj->description);
}

int Object_init(void *self){
    // do nothing really
    return 1;
}

void *Object_move(void *sefl, Direction direction){
    printf("You can't go that direction.\n");
    return NULL;
}

int Object_attack(void *self, int damage){
    printf("You can't attack that.\n");
    return 0;
}

void *Object_new(size_t size, Object proto, char *description){
    // setup the default functions in case they aren't set
    if(!proto.init) proto.init = Object_init;
    if(!proto.describe) proto.describe = Object_describe;
    if(!proto.destroy) proto.destroy = Object_destroy;
    if(!proto.attack) proto.attack = Object_attack;
    if(!proto.move) proto.move = Object_move;

    // this seems weird, but we can make a struct of one size,
    // then point a different pointer at it to "cast" it
    Object *el = calloc(1, size);
    *el = proto;

    // copy the description over 
    el->description = strdup(description);

    // initialize it with whatever init we were given
    if(!el->init(el)){
        // looks like it didn't initialize properly
        el->destroy(el);
        return NULL;
    }
    else {
        //all done, we made an object of any type
        return el;
    }
}

ex19.h:

#ifndef __ex19_h
#define __ex19_h

#include "object.h"

struct Monster {
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;

int Monster_attack(void *self, int damage);
int Monster_init(void *self);

struct Room{
    Object proto;

    Monster *bad_guy;

    struct Room *north;
    struct Room *south;
    struct Room *east;
    struct Room *west;
};

typedef struct Room Room;

void *Room_move(void *self, Direction direction);
int Room_attack(void *self, int damage);
int Room_init(void *self);

struct Map{
    Object proto;
    Room *start;
    Room *location;
};

typedef struct Map Map;

void *Map_move(void *self, Direction direction);
int Map_attack(void *self, int damage);
int Map_init(void *self);

#endif

ex19.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include "ex19.h"

int Monster_attack(void *self, int damage){
    Monster *monster = self;
    printf("You attack %s!\n", monster->_(description));
    monster->hit_points -= damage;
    if(monster->hit_points > 0) {
        printf("It is still alive.\n");
        return 0;
    }
    else{
        printf("It is dead!\n");
        return 1;
    }
}

int Monster_init(void *self){
    Monster *monster = self;
    monster->hit_points = 10;
    return 1;
}

Object MonsterProto = {
    .init = Monster_init,
    .attack = Monster_attack
};

void *Room_move(void *self, Direction direction) {
    Room *room = self;
    Room *next = NULL;

    if(direction == NORTH && room->north) {
        printf("You go north, into:\n");
        next = room->north;
    }
    else if(direction == SOUTH && room->south){
        printf("You go south, into:\n");
        next = room->south;
    }
    else if(direction == EAST && room->east){
        printf("You go east, into:\n");
        next = room->east;
    }
    else if(direction == WEST && room->west){
        printf("You go west, into:\n");
        next = room->west;
    }
    else {
        printf("You can't go that direction.");
        next = NULL;
    }

    if(next){
        next->_(describe)(next);
    }
    return next;
}

int Room_attack(void *self, int damage){
    Room *room = self;
    Monster *monster = room->bad_guy;

    if(monster){
        monster->_(attack)(monster, damage);
        return 1;
    }
    else{
        printf("You flail in the air at nothing. Idiot.\n");
        return 0;
    }
}

Object RoomProto = {
    .move = Room_move,
    .attack = Room_attack
};

void *Map_move(void *self, Direction direction){
    Map *map = self;
    Room *location = map->location;
    Room *next = NULL;

    next = location->_(move)(location, direction);
    if(next) {
        map->location = next;
    }
    return next;
}

int Map_attack(void *self, int damage){
    Map* map = self;
    Room *location = map->location;
    return location->_(attack)(location, damage);
}

int Map_init(void *self){
    Map *map = self;

    //make some rooms for a small map
    Room *hall = NEW(Room, "The great hall");
    Room *throne = NEW(Room, "The throne room");
    Room *arena = NEW(Room, "The arena, with the minotaur");
    Room *kitchen = NEW(Room, "Kitchen, you have the knife now");

    // put the bad guy in the arena
    arena->bad_guy = NEW(Monster, "The evil minotaur");

    // setup the map rooms 
    hall->north = throne;

    throne->west = arena;
    throne->east = kitchen;
    throne->south = hall;

    arena->east = throne;
    kitchen->west = throne;

    //start the map and the character off in the hall 
    map->start = hall;
    map->location = hall;

    return 1;
}

Object MapProto = {
    .init = Map_init,
    .move = Map_move,
    .attack = Map_attack
};

int process_input(Map *game){
    printf("\n> ");
    char ch = getchar();
    getchar();  // eat enter;

    int damage = rand() % 4;
    switch(ch){
        case -1:
            printf("Giving up? You such.\n");
            return 0;
            break;
        case 'n':
            game->_(move)(game, NORTH);
            break;
        case 's':
            game->_(move)(game, SOUTH);
            break;
        case 'e':
            game->_(move)(game, EAST);
            break;
        case 'w':
            game->_(move)(game, WEST);
            break;
        case 'a':
            game->_(attack)(game, damage);
            break;
        case 'l':
            printf("You can go:\n");
            if(game->location->north) printf("NORTH\n");
            if(game->location->south) printf("SOUTH\n");
            if(game->location->east) printf("EAST\n");
            if(game->location->west) printf("WEST\n");
            break;
        default:
            printf("What?: %d\n", ch);
    }
    return 1;
}

int main(int argc, char *argv[]){
    //simple way to setup the randomness
    srand(time(NULL));

    //make our map to work with
    Map *game = NEW(Map, "The hall of the Minotaur.");
    printf("You enter the ");
    game->location->_(describe)(game->location);
    while(process_input(game)) {
    }
    return 0;
}

编译错误:

cc -Wall -g -o ex19 ex19.c /tmp/cccuR81O.o:在函数Map_init': ex19/ex19.c:105: undefined reference to Object_new'中 ex19 / ex19.c:106:对Object_new' ex19/ex19.c:107: undefined reference to Object_new'的未定义引用 ex19 / ex19.c:108:对Object_new' ex19/ex19.c:111: undefined reference to Object_new'的未定义引用 ex19 / ex19.c:180:对“Object_new”的更多未定义引用如下 collect2:错误:ld返回1退出状态 make:*** [all]错误1

更新1:有问题的行

105  Room *hall = NEW(Room, "The great hall");
106  Room *throne = NEW(Room, "The throne room");
107  Room *arena = NEW(Room, "The arena, with the minotaur");
108  Room *kitchen = NEW(Room, "Kitchen, you have the knife now");

111  arena->bad_guy = NEW(Monster, "The evil minotaur");

1 个答案:

答案 0 :(得分:2)

需要更新makefile以将object.o链接到可执行文件中。目前您的链接行是:

cc $(CFLAGS) -o ex19 $(src)

如果执行make(或make all),则命令将扩展为:

cc -Wall -g -o ex19 ex19.c

尝试仅使用ex19.c生成可执行文件。

永远不会调用构建目标ex19,因为all没有将它作为依赖项。但即使它确实如此,或者您手动编写make ex19,仍然只会object.o,您在任何可以将ex19.oobject.o关联起来的命令都没有可执行文件。

您应该将src = ex19.c更改为src = ex19.c object.c,因为这些都是源文件。你可以取出ex19: object.o行,因为它在这里是多余的。这个makefile将编译并链接一行中的所有源文件,这很好。

如果要更改makefile以对每个.c文件使用编译器的单独调用(因此需要对链接器进行第三次调用),那么您需要进行一些更改,这可能是最好的从现有的模型中模拟你的makefile。