gcc""的多重定义错误

时间:2016-03-24 20:51:21

标签: c gcc

所以我有这三个文件

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

我不相信我不止一次宣布这些方法,而且它的格式也与我通常给出的格式大不相同。不太清楚这意味着什么。

3 个答案:

答案 0 :(得分:9)

问题是你的头文件中有函数和全局定义(而不是声明)。因此,这些函数在编译时会被拉入main.c和support.c中。然后在链接阶段,链接器会看到多个定义。

即使你有包含警卫,在这种情况下它也无济于事,因为它只能防御单个编译单元中的多个定义,而不是多个单元。

从头文件中取出这些函数的定义,用声明替换它们,并将它们放在support.c或单独的.c文件中。

答案 1 :(得分:0)

确保标题仅包含一次,因此请在标题源代码中添加以下内容:

#ifndef _HAVE_SUPPORT_H
#define _HAVE_SUPPORT_H

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


#endif //_HAVE_SUPPORT_H

正如我所说,这确保标题只包含一次,因为它定义了_HAVE_SUPPORT_H。如果现在另一个源尝试包含它,它将不会执行任何操作,因为已经定义了_HAVE_SUPPRORT_H

如果标题中只有函数声明,而且“真正的”函数将放在另一个*.c文件中,它也会有所帮助。

编辑: 第二部分对你的问题最重要,因为@kaylum注意到了

答案 2 :(得分:0)

您可以对 gcc 使用 -fcommon 选项。