gpt4 book ai didi

c - C:将主要功能移至新文件时出现段错误

转载 作者:行者123 更新时间:2023-12-01 12:42:35 26 4
gpt4 key购买 nike

我实现了一个自定义的内存分配器。我为此内部文件memory.c编写的所有主要代码都在该文件中创建了一个主要功能以测试功能。一切正常。但是,当我将这些测试代码移动到另一个文件(调用main.c并运行它。遇到分段错误)。

int main (int argc, char *argv []) {
allocator_init();
char* ptr = (char*) allocate(4096); // csutom function. that on `memory.c`
strcpy(ptr, "this is the test one");// segmentation fault here
printf("print: %s\n", ptr);
deallocate(ptr);
}

这是主要代码:
volatile Memory memory;


/* allocated memory to memory variable by assign /dev/zero to memory */
void allocator_init() {
fd = open("/dev/zero", O_RDWR);
if(fd == -1) {
perror("File open failed");
exit(0);
}

// page size can different on different platform. customize again to optimize
PAGE_SIZE = getPageSize();

// fd = open("ZEROES", O_RDWR);

if(fd == -1) {
perror("File open failed");
exit(0);
}

// Initialize the region list
memory.region = NULL;

int i;
/// Initialize the caches
/// size of each cache is 16 * 2^i => 16, 32, 64, 128, 256, 512, 1024, 2048
for (i=0; i<8; i++) {
memory.cache[i].size = 16<<i;
memory.cache[i].S = NULL;
}
return;
}

void *allocate_region (unsigned int size) {

Region *region, *temp;

temp = memory.region;
void *mapped_addr = mmap(NULL, size + REGION_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);

if(mapped_addr == MAP_FAILED) {
perror("Mapping failed");
exit(0);
}

/* create region from mapped address */
region = mapped_addr;
region->size = size;
region->addr = mapped_addr + REGION_SIZE;
printf("allocated region: %p\n", region->addr);

/* assign this region to memory */
memory.region = region;

/* just simple append algorithm in linked list. so new region will be appended to head of linked list */
region->next = temp;

return region->addr;

}

/* allocate : if size < 2048 : allocate cache. else allocate region */
void *allocate(unsigned int size) {
size = ALIGN(size);
return allocate_region(size);
}

这是 memory.h定义我使用过的所有结构:
#ifndef MEMORY_H
#define MEMORY_H

#define MAX_SIZE (1024*1024)
#define REGION_SIZE sizeof(Region)
#define SLAB_SIZE sizeof(Slab)
#define WORD_SIZE 32
#define ALIGNMENT 8
/* rounds up to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
#define TRUE 1
#define FALSE 0
#define MAX_SIZE 10000

// Caches are:
// 16, 32, 64, 128, 256, 512, 1024, 2048


#include "bits.h"

int PAGE_SIZE;
// File descriptor for zeroes file
int fd;

void allocator_init();
int deallocate_cache(void* ptr);
void *allocate(unsigned int size);


typedef struct __Region {
void *addr; /// started address can use for caller (can calc by allocated address + Region size)
int size; /// size of this allocated Region (not include size Region)
struct __Region *next;
} Region;

/// size of Slab equals to size of System Page
typedef struct __Slab {
void *addr; /// address of this slab (exclude header)
char *bitmap; /// started address can use for caller (can calc by allocated address + slab size)
int size;
int slots; /// number of slots in maximum has been used
int cache_size; /// size of cache that contains this slab
int bitmap_size; /// size of bitmap. so, can count address bit by bitmap + bitmap_size
int currentSize; /// current allocated elements of this slab. currentSize = 0. deallocated this slab
int bit; /// bit to marked which part of slab has been used
struct __Slab * next;
} Slab;



typedef struct __Cache {
int size;
Slab *S;
} Cache;


typedef struct __Memory {
Region *region;
Cache cache[8];
} Memory;
#endif // MEMORY_H

上面的代码可以正常工作, allocate函数返回一个地址。移动到另一个文件时遇到错误。在我的 memory.c中,我有一些全局变量来控制分配的地址和内存。将代码移到新文件时会影响吗?我无法解释这一点。

谢谢 :)

最佳答案

有一些值得观察的发现:

  • 标头应仅声明代码使用者需要了解的内容。这是三个函数:allocator_init()allocate()deallocate_cache()。文件中的其他所有内容都是实现细节,应从代码使用者中隐藏。
  • 标头不应定义变量,甚至不能临时定义。如果您没有在标头中的变量前面编写extern,则应在其前面加上static,您最好有一个很好的理由。 (有关详细信息,请参见How do I share a variable between source files in C。)
  • 保留以_开头的名称,以供实现使用。这有点过分简化,但是它涵盖了所有基础,并且比形式正确的规则更容易记住。以__开头的名称绝对是禁止使用的(100%;不涉及任何简化)。不要为自己定义这样的名称,并且要非常谨慎地在代码中使用这样的名称(它们通常是您不应该使用的类型)。我只是从结构标签中删除了下划线。它工作愉快。
  • 您的标头包含"bits.h",但是幸运的是您的代码未使用其中的任何内容,因此将其注释掉是可以的。
  • 您的代码使用getPageSize(),但未定义它。可能是可以原谅的;我改用4096。并跟踪下来表明PAGE_SIZE是标头中定义的变量,导致此diatribe辩论开始,说明了要做什么。它应该是static文件中的memory.c变量。从源文件外部可见的唯一内容应该是使用者需要使用的那些函数(也许还有全局变量)。其他所有内容均应为static,以使其不可见-名称不冲突,不存在滥用或滥用的可能性。
  • 当将其制成静态变量时,编译器会抱怨PAGE_SIZE未使用。顺便说一句,这是将所有可以静态化的内容变成静态定义的另一个优点-当由于非静态而可以在源代码外部访问代码时,编译器不会警告未使用的变量或函数。
  • 您的标头为MAX_SIZE定义了两个不同的值;别!
  • 您的标头定义了未使用的值,例如#define TRUE 1;再次,不要。 (也没有使用MAX_SIZE,也没有使用FALSE,也没有使用SLAB_SIZE,...)
  • 您的ALIGN宏有故障:
     #define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~0x7)

    就目前而言,ALIGNMENT是8,并且宏起作用。但是假设我将ALIGNMENT更改为16;那面具就错了它可能应该是& ~(ALIGNMENT - 1)。当心明显的参数化是不完整的。
  • 如果由于错误退出,则不应以状态0退出;这意味着成功。请使用1或EXIT_FAILURE-或遵循其他一些与本地相关的方案。
  • 您的标头声明了deallocate_cache(),但是您的主程序调用了deallocate(),但没有给出两者的代码。命名不一致是有问题的。我使用了一个虚拟实现。

  • 显然,也必须添加必要的标题。好;固定好该代码后,代码便会编译并链接起来。然后我遇到了:
    Mapping failed: Operation not supported by device

    这是Mac OS X 10.9.2 Mavericks。仅供参考。我通过创建一个空文件 ./dev.zero并引用它来解决此问题。当心可移植性假设。

    然后它因总线错误(信号10)而崩溃。它没有打印 allocated region消息。这样可以将损坏限制在3行代码之内。

    您不能在标准C语言中对 void *类型进行算术运算。但是,在具有任何可移植性的代码中,请不要利用它。

    当我创建一个空文件时,程序崩溃了。当我使用 dd if=/dev/zero of=dev.zero bs=1k count=1024将文件初始化为全零时,该程序不再崩溃。我添加了一堆调试打印代码。

    我建议不要将 /dev/zero用于映射文件。
    Mapping succeeded: 0x10ca74000
    region = 0x10ca74000
    size = 4096
    allocated region: 0x10ca74018
    Memory: allocate_region (0x10ca40080)
    Region: Base (0x10ca74000)
    Address: 0x10ca74018, size: 4096, next = 0x0
    Cache: line 0 (0x10ca40088)
    Size: 16
    Cache: line 1 (0x10ca40098)
    Size: 32
    Cache: line 2 (0x10ca400a8)
    Size: 64
    Cache: line 3 (0x10ca400b8)
    Size: 128
    Cache: line 4 (0x10ca400c8)
    Size: 256
    Cache: line 5 (0x10ca400d8)
    Size: 512
    Cache: line 6 (0x10ca400e8)
    Size: 1024
    Cache: line 7 (0x10ca400f8)
    Size: 2048
    ptr = 0x10ca74018
    print: this is the test one
    deallocate called for 0x10ca74018: unimplemented



    内存
    #ifndef MEMORY_H
    #define MEMORY_H

    extern void allocator_init(void);
    extern void deallocate(void *ptr);
    extern void *allocate(unsigned int size);

    #endif // MEMORY_H

    main.c
    #include <stdio.h>
    #include <string.h>
    #include "memory.h"

    int main(void)
    {
    allocator_init();
    char *ptr = (char *) allocate(4096); // custom function. that on `memory.c`
    printf("ptr = %p\n", ptr);
    strcpy(ptr, "this is the test one"); // segmentation fault here
    printf("print: %s\n", ptr);
    deallocate(ptr);
    }

    内存
    #include "memory.h"
    #include <assert.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <unistd.h>

    #define REGION_SIZE sizeof(Region)

    #define ALIGNMENT 8
    #define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))

    #if defined(DEV_ZERO_MEMORY_MAPPING)
    #define DEV_ZERO "/dev/zero"
    #else
    #define DEV_ZERO "./dev.zero"
    #endif

    enum { NUM_CACHES = 8 };

    static int fd = -1;

    typedef struct Region
    {
    void *addr;
    int size;
    struct Region *next;
    } Region;

    typedef struct Slab
    {
    void *addr;
    char *bitmap;
    int size;
    int slots;
    int cache_size;
    int bitmap_size;
    int currentSize;
    int bit;
    struct Slab *next;
    } Slab;

    typedef struct Cache
    {
    int size;
    Slab *S;
    } Cache;

    typedef struct Memory
    {
    Region *region;
    Cache cache[NUM_CACHES];
    } Memory;

    static Memory memory = { 0 };

    static void dump_slab(FILE *fp, const char *tag, const Slab *slab)
    {
    fprintf(fp, "Slab: %s (%p)\n", tag, slab);
    if (slab != 0)
    {
    fprintf(fp, "addr: %p, ", slab->addr);
    fprintf(fp, "bitmap: %p, ", (void *)slab->bitmap);
    fprintf(fp, "size: %6d, slots %3d, ", slab->size, slab->slots);
    /*
    int cache_size;
    int bitmap_size;
    int currentSize;
    int bit;
    struct Slab *next;
    */
    }
    }

    static void dump_cache(FILE *fp, const char *tag, const Cache *cache)
    {
    fprintf(fp, "Cache: %s (%p)\n", tag, cache);
    if (cache != 0)
    {
    fprintf(fp, "Size: %d\n", cache->size);
    Slab *slab = cache->S;
    while (slab != 0)
    {
    dump_slab(fp, "", slab);
    slab = slab->next;
    }
    }
    }

    static void dump_region(FILE *fp, const char *tag, const Region *reg)
    {
    fprintf(fp, "Region: %s (%p)\n", tag, reg);
    if (reg != 0)
    {
    fprintf(fp, "Address: %p, size: %6d, next = %p\n",
    reg->addr, reg->size, reg->next);
    }
    }

    static void dump_memory(FILE *fp, const char *tag, const Memory *mem)
    {
    fprintf(fp, "Memory: %s (%p)\n", tag, mem);
    if (mem != 0)
    {
    Region *reg = mem->region;
    dump_region(fp, "Base", reg);
    while (reg->next != 0)
    {
    dump_region(fp, "Next", reg->next);
    reg = reg->next;
    }
    for (int i = 0; i < NUM_CACHES; i++)
    {
    char line[32];
    snprintf(line, sizeof(line), "line %d", i);
    dump_cache(fp, line, &memory.cache[i]);
    }
    }
    }

    void allocator_init(void)
    {
    fd = open(DEV_ZERO, O_RDWR|O_CREAT, 0600);
    if (fd == -1)
    {
    perror("File open failed");
    exit(0);
    }

    if (fd == -1)
    {
    perror("File open failed");
    exit(0);
    }

    memory.region = NULL;

    for (int i = 0; i < NUM_CACHES; i++)
    {
    memory.cache[i].size = 16 << i;
    memory.cache[i].S = NULL;
    }
    }

    static void *allocate_region(unsigned int size)
    {
    assert(fd != -1);

    Region *temp = memory.region;
    void *mapped_addr = mmap(NULL, size + REGION_SIZE, PROT_READ | PROT_WRITE,
    MAP_PRIVATE, fd, 0);

    if (mapped_addr == MAP_FAILED)
    {
    perror("Mapping failed");
    exit(0);
    }
    printf("Mapping succeeded: %p\n", mapped_addr);

    Region *region = mapped_addr;
    printf("region = %p\n", region);
    region->size = size;
    printf("size = %d\n", region->size);
    region->addr = (char *)mapped_addr + REGION_SIZE;
    printf("allocated region: %p\n", region->addr);

    memory.region = region;
    region->next = temp;

    dump_memory(stderr, __func__, &memory);

    return region->addr;
    }

    void *allocate(unsigned int size)
    {
    size = ALIGN(size);
    return allocate_region(size);
    }

    void deallocate(void *ptr)
    {
    fprintf(stderr, "%s called for %p: unimplemented\n", __func__, ptr);
    }

    我强烈建议使函数沿着所示的 dump_memory()dump_region()dump_cache()dump_slab()函数转储复杂的结构;它们通常非常有帮助,尽管它们实际上在调试时有些麻烦。

    关于c - C:将主要功能移至新文件时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22885179/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com