2014-12-22 2 views
-3

Я застрял в этой ошибке компиляции, и мне интересно, как отлаживать код. Моя программа в основном имеет следующие файлы:Как удалить неопределенную ссылку в моем коде?

Makefile:

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; 
} 

Ошибка компиляции:

куб.см -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: ошибка: Л.Д. возвращается 1 статус выхода сделать: *** [все] Ошибка 1

Update 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"); 
+0

Знаете ли вы, что в кодовых дампах нет номеров строк? –

+0

Извините, я обновил номера строк. – drdot

ответ

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.o с object.o, чтобы сделать исполняемый файл.

Вы должны изменить src = ex19.c как src = ex19.c object.c, так как оба являются исходными файлами. Вы можете вынуть линию ex19: object.o, так как здесь она избыточна. Этот make-файл будет компилировать и связывать все исходные файлы в одной строке, что отлично.

Если вы хотите изменить свой файл makefile, чтобы использовать отдельные вызовы компилятора для каждого файла .c (и, следовательно, третьего вызова, необходимого для компоновщика), вам нужно сделать несколько изменений, вероятно, лучше всего смоделировать ваши makefile от существующего.

+0

Спасибо за ответ. Это работает!Не могли бы вы добавить пример при создании файла makefile, чтобы использовать отдельные вызовы компилятора для каждого .c-файла, а затем для вызова компоновщика? Мне интересно узнать это. – drdot

+0

@ dannycrane [см. Здесь] (http://stackoverflow.com/a/2481307/1505939) для примера. Вы можете автоматизировать его, так что вам просто нужно предоставить '$ (src)', а все остальные правила преобразуют этот список c-файлов, но полезно сначала понять основы –

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