2016-03-24 4 views
3

Поэтому у меня есть эти три файлаНКУ "множественное определение" ошибки

main.C

#include <assert.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <stdio.h> 
#include "support.h" 

int main(void) { 
    int* num1 = malloc(100); 
    printf("num1: %p", &num1); 
} 

Support.c

#include <assert.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include "support.h" 

void *malloc(size_t size) { 
    struct block_meta *block; 
    if (size <= 0) { 
     return NULL; 
    } 
    if (!global_base) { // First call. 
    block = request_space(NULL, size); 
     if (!block) { 
      return NULL; 
     } 
     global_base = block; 
    } else { 
     struct block_meta *last = global_base; 
     block = find_free_block(&last, size); 
     if (!block) { // Failed to find free block. 
      block = request_space(last, size); 
      if (!block) { 
       return NULL; 
      } 
     } else { // Found free block 
      block->free = 0; 
      block->magic = 0x77777777; 
     } 
    } 
    return(block+1); 
} 


void free(void *ptr) { 
    if (!ptr) { 
     return; 
    } 
    struct block_meta* block_ptr = get_block_ptr(ptr); 
    assert(block_ptr->free == 0); 
    assert(block_ptr->magic == 0x77777777 || block_ptr->magic == 0x12345678); 
    block_ptr->free = 1; 
    block_ptr->magic = 0x55555555; 
} 

void *realloc(void *ptr, size_t size) { 
    if (!ptr) { 
     // NULL ptr. realloc should act like malloc. 
     return malloc(size); 
    } 
    struct block_meta* block_ptr = get_block_ptr(ptr); 
    if (block_ptr->size >= size) { 
     // We have enough space. Could free some once we implement split. 
     return ptr; 
    } 
    // Need to really realloc. Malloc new space and free old space. 
    // Then copy old data to new space. 
    void *new_ptr; 
    new_ptr = malloc(size); 
    if (!new_ptr) { 
     return NULL; // TODO: set errno on failure. 
    } 
    memcpy(new_ptr, ptr, block_ptr->size); 
    free(ptr); 
    return new_ptr; 
} 

void *calloc(size_t nelem, size_t elsize) { 
    size_t size = nelem * elsize; // TODO: check for overflow. 
    void *ptr = malloc(size); 
    memset(ptr, 0, size); 
    return ptr; 
} 

Support.h

#include <assert.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 

void *malloc(size_t size); 
void free(void *ptr); 
void *realloc(void *ptr, size_t size); 


struct block_meta { 
    size_t size; 
    struct block_meta *next; 
    int free; 
    int magic; // For debugging only. TODO: remove this in non-debug mode. 
}; 

#define META_SIZE sizeof(struct block_meta) 

void *global_base = NULL; 

struct block_meta *find_free_block(struct block_meta **last, size_t size) { 
    struct block_meta *current = global_base; 
    while (current && !(current->free && current->size >= size)) { 
     *last = current; 
     current = current->next; 
    } 
    return current; 
} 

struct block_meta *request_space(struct block_meta* last, size_t size) { 
    struct block_meta *block; 
    block = sbrk(0); 
    void *request = sbrk(size + META_SIZE); 
    assert((void*)block == request); // Not thread safe. 
    if (request == (void*) -1) { 
     return NULL; // sbrk failed. 
    } 
    if (last) { // NULL on first request. 
     last->next = block; 
    } 
    block->size = size; 
    block->next = NULL; 
    block->free = 0; 
    block->magic = 0x12345678; 
    return block; 
} 

struct block_meta *get_block_ptr(void *ptr) { 
    return (struct block_meta*)ptr - 1; 
} 

Однако, когда я пытаюсь скомпилировать, используя

gcc -o asgn2 main.c support.c 

Я получаю ошибку

/tmp/ccscmcbS.o:(.bss+0x0): multiple definition of `global_base' 
/tmp/ccyjhjQC.o:(.bss+0x0): first defined here 
/tmp/ccscmcbS.o: In function `find_free_block': 
support.c:(.text+0x0): multiple definition of `find_free_block' 
/tmp/ccyjhjQC.o:main.c:(.text+0x0): first defined here 
/tmp/ccscmcbS.o: In function `request_space': 
support.c:(.text+0x55): multiple definition of `request_space' 
/tmp/ccyjhjQC.o:main.c:(.text+0x55): first defined here 
/tmp/ccscmcbS.o: In function `get_block_ptr': 
support.c:(.text+0xfe): multiple definition of `get_block_ptr' 
/tmp/ccyjhjQC.o:main.c:(.text+0xfe): first defined here 
collect2: error: ld returned 1 exit status 

Я не верю, что я объявил эти методы более чем один раз, и это в гораздо ином формате, чем я обычно дается. Не совсем уверен, что это значит.

+1

Дубликат http://stackoverflow.com/questions/34748913/lnk2005-error-in-clr-windows-form. Он находится на _Win_, но это одно и то же: Определения внутри файла заголовка (включены в несколько исходных файлов). – CristiFati

+0

Поиск «заголовка C включают в себя охранники» в Google для получения дополнительной информации. – Harry

ответ

0

Убедитесь, что заголовок включается только один раз, так что добавить что-то вроде следующего в заголовки исходного кода:

#ifndef _HAVE_SUPPORT_H 
#define _HAVE_SUPPORT_H 

// ... 
// YOUR HEADER SOURCE CODE 
// ... 


#endif //_HAVE_SUPPORT_H 

Как я сказал, это гарантирует, что заголовок включается только один раз, потому что тогда это определяет _HAVE_SUPPORT_H. Если теперь другой источник пытается включить его, он ничего не сделает, потому что _HAVE_SUPPRORT_H уже определен.

Это также помогает, если у вас есть только объявления функций в заголовке, а ваши «реальные» функции будут в другом файле *.c.

Edit: Вторая часть является наиболее важной для вашей проблемы, как @kaylum заметил

+0

Обратите внимание, что включение охранников не решает проблему OP, поскольку заголовок включен в два разных файла .c. «Если теперь другой источник пытается включить его, он ничего не сделает», это не совсем правильно. Другой исходный файл может содержать один и тот же заголовок и получать те же определения, что приводит к нескольким определениям. Последний пункт на самом деле является решающим моментом и, следовательно, должен быть сформулирован более строго (не «может» он должен быть «обязательным» в случае OP). – kaylum

+0

Вы правы, я отредактирую ответ – mame98

3

Проблемы заключается в том, что у вас есть функции и глобал определенных (в отличие от объявлено) в файле заголовок. Поэтому эти функции вставляются в main.c и support.c при их компиляции. Затем во время фазы связывания линкер видит несколько определений.

Даже если у вас есть защитники, в этом случае это не поможет, потому что это защищает только от нескольких определений в одном блоке компиляции, а не в нескольких единицах.

Выполните определения этих функций из файла заголовка, замените их декларациями и поместите их либо в файл support.c, либо в отдельный файл .c.

+0

То же самое для глобальных переменных, 'global_base' определен (объявление с начальным значением) в заголовке, и поэтому он определяется дважды. – jdarthenay

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