RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 931337
Accepted
Peter Levenberg
Peter Levenberg
Asked:2020-01-13 00:07:30 +0000 UTC2020-01-13 00:07:30 +0000 UTC 2020-01-13 00:07:30 +0000 UTC

数组上的自定义 malloc

  • 772

我怀疑这是一个愚蠢的问题。但我无法得到答案。假设我们有一段记忆:

void *mem = malloc(32);

假设您想创建一些东西,例如:

int *ptr;

这样这个东西就位于 address&mem,就像在工会中发生的那样。

目标是尝试实现一个小的malloc。

这是现有测试代码的示例,其中在数组外部创建了一个新指针(而不是应有的样子)(只是不要发誓,不要smack):

int main(void){
    void *mem,*mpt;

    if( (mpt=mem=malloc(32)) == NULL )
        puts("Allocation error!"),abort();

    unsigned long *ctm;
    ctm=mpt;
    mpt+=sizeof(ctm);
    *ctm=13;

    printf("mem [%p] %p     \n", &mem, mem     );
    printf("mpt [%p] %p     \n", &mpt, mpt     );
    printf("ctm [%p] %p %lu \n", &ctm, ctm,*ctm);

    return 0;}

我收集所以:cc -Werror -o Test Test.c -std=c11

显然,带有装配插件的变体不适合,因为 需要为不同架构的组装保留多功能性。

c
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. AnT stands with Russia
    2020-01-13T00:12:06Z2020-01-13T00:12:06Z
    1. 如果您通过调用为新对象分配内存

      void *mem = malloc(32); 
      

      那么这个新对象将位于该地址mem,而不是该地址&mem。&mem这里绝对没有。

    2. C 语言不支持void *指针的地址算术。要执行字节地址算术,必须将指针转换为 type char *。

    3. 在为该类型的对象分配内存后unsigned long,您需要将指针移至sizeof(unsigned long),也就是说sizeof *ctm,而不是sizeof ctm

    那不是

    mpt+=sizeof(ctm);
    

    一个

    mpt = (char *) mpt + sizeof *ctm;
    

    否则,一切都会正确完成。但是,一般来说,如果您谈论的是“不同架构的程序集”,则不应忘记对齐要求。

    您在评论中的其余问题中所谈论的内容并不完全清楚。C 语言不允许在特定地址声明变量。在显式声明的数组(从迂腐的角度来看,这并不完全合法)中的内存本地分配可以按照您在上面所做的相同方式进行组织。数组是通过分配malloc还是显式声明 - 无关紧要。同样,请记住对齐要求。

    • 7
  2. Best Answer
    MGNeo
    2020-01-16T13:27:55Z2020-01-16T13:27:55Z
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv)
    {
        // Количество байтов в массиве.
        const size_t count = 1024;
    
        // Попытка выделить память под массив.
        char *const memory = malloc(count);
        // Контроль успешности выделения памяти.
        if (memory == NULL)
        {
            printf("malloc() error\n");
            abort();
        }
    
        // Адрес доступного вам участка памяти хранится в стековой переменной memory.
        // Вы вольны делать с этой памятью все, что хотите.
    
        // Можете использовать ее как массив байтов.
        for (size_t i = 0; i < count; ++i)
        {
            memory[i] = i;
        }
    
        // Можете как угодно типизировать участки этой памяти.
        // Это можно делать средствами C или ассемблерными вставками.
        // Вы вольны не использовать вспомогательную память, а работать напрямую с заданными адресами.
        // Важно учитывать выравнивание, потому что неверное выравнивание приводит к неопределенному поведению.
        *( (float*) memory ) = 1.11111f;// OK
        *( (void**) (memory + sizeof(float)) ) = NULL;// OK
        *( (int*) (memory + 3) ) = 3;// UB
    
        // Вы вольны использовать шаблон разметки памяти.
        struct my_struct
        {
            int i;
            double d;
        };
    
        // Используя для удобства работы типизированный указатель, лежащий на стеке.
        struct my_struct *const ms = (struct my_struct*) memory;
        ms->i = 1;
        ms->d = 2.222222;
    
        // Либо работать без такового.
        ( (struct my_struct*) memory )->i = 1;
        ( (struct my_struct*) memory )->d = 2.222222;
    
        // Если вас смущает косвенное обращение к данным через указатель посредством операции ->,
        // то вы можете использовать прием *массив из одного элемента*.
        ms[0].i = 1;
        ms[0].d = 2.222222;
    
        // Или можете считать, что элемент не один.
        for (size_t i = 0; i < 5; ++i)
        {
            ms[i].i = i;
            ms[i].d = 2.2222 * i;
        }
    
        // Если вам не нравится то, что void *ptr размещает указатель на стеке,
        // никто вам не запрещает использовать макроопределение, которое задаст
        // имя любому указанному и типизированному вами куску памяти.
        // Правда, в этом случае многие IDE не смогут вам помощь с подсветкой и
        // автодополнением такого кода.
        #define my_void_ptr ( *((void**) memory) )
        my_void_ptr = NULL;
        #undef my_void_ptr
    
        free(memory);
    
        return 0;
    }
    

    如果你想实现一个小 malloc()的,那么我认为这没有障碍。

    但是,重要的是要记住,本机 malloc()非常复杂。此外,该设备因编译器、运行时库和操作系统而异。

    在内部,本机 malloc()通常调用操作系统,向它请求内存,通常在整个页面中并有一些余量。因此,许多小型的malloc()通常工作得很快。

    malloc()您可以使用针对特定使用策略优化的各种现有实现。

    可以制作一种快速且经济malloc()的适用于堆栈内存的产品。这通常在资源非常有限的系统中完成,例如,在对控制器进行编程时,无论它们是工业系统、嵌入式设备还是游戏机,例如NES(ala Dendy)。

    有一个函数_alloca()(或alloca())。这是一个类似物malloc(),它不是从堆中分配内存,而是从线程的堆栈中分配内存。不建议使用此函数,因为有许多难以理解的细微之处和警告,尤其是在深层调用堆栈中,尤其是在使用宏时。但如果你真的想,那么你可以。

    • 3

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5