【问题标题】:Assigning pointers of different type to existing memory将不同类型的指针分配给现有内存
【发布时间】:2018-11-24 01:16:35
【问题描述】:

我试图写一个与类型无关的mem_take
它需要预先分配内存并将其块分配给几个指针。这些指针可以指向不同的类型:浮点数、双精度数等。

unsigned int mem_take( void** mem_input, void** mem_pos, const int size_bytes, const int alignment )
{
    // get address
    unsigned int addr = (unsigned int)*mem_pos;

    // align
    unsigned int adjustment_bytes = 0;
    unsigned int misalignment = addr % alignment;
    if(misalignment != 0)
    {
        adjustment_bytes = alignment - misalignment;
        addr += adjustment_bytes;
    }

    // take aligned address
    *mem_input = (void*)addr;

    // move current position to next free location
    addr += size_bytes;
    *mem_pos = (void*)addr;

    // return bytes taken
    return (size_bytes + adjustment_bytes);
}

例子:

main()
{
    char mem[SOME_SIZE];
    void* mem_pos = mem;

    float*  f;
    double* d;
    int bytes_taken_f = mem_take((void**)&f , &mem_pos, 2 * sizeof(float) , 8); // 2 floats
    int bytes_taken_d = mem_take((void**)&d , &mem_pos, 3 * sizeof(double), 8); // 3 doubles
    // etc.

    // now free to use the memory via arrays
    f[0] = 1.0f;
    f[1] = 2.0f;

    d[0] = 1.0f;
    d[1] = 2.0f;
    d[2] = 3.0f;
}

这样做的原因是平台——一个内存非常有限的 DSP 处理器。 (说来话长。)

这个解决方案有效吗? mem_take写对了吗?

附言 请注意,实际用例是定点 DSP 处理器,因此上面的示例被“简化”为类型不会是浮点数、双精度数,而是特定于处理器的类型。

【问题讨论】:

  • 使用 unsigned long addr = (unsigned long)*mem_pos
  • 这更适合 CodeReview 堆栈交换站点,因为它是您想要建议和 cmets 的工作代码,而不是“编程问题”。但在我看来一般都还可以! :)
  • 这根本不符合严格要求。它打破了严格的混叠。此外,void ** 不是 通用指针类型 - 即使是显式转换的要求也会告诉您您正在做一些可疑的事情。因此,在不确切知道您正在使用的编译器实现的情况下,我们根本无法评论任何内容。
  • 也许这个stackoverflow.com/a/22624888/4386427对你来说会很有趣
  • 假设编译器是 GCC 7.3。

标签: c


【解决方案1】:

在做:

 void f(void **f);
 float a;
 f((void**)&a);

不是一个好主意,因为void** 不可移植。需要取void*变量的地址:

 void f(void **f);
 float a;
 void *tmp = &a;
 f(&tmp);

,但你可以像 malloc 一样返回 void*
这就像编写在自定义堆栈上分配内存的简单 malloc 函数。

#include <stdio.h>
#include <stdint.h>
#include <assert.h>

void *mem_take(void **mem, size_t *memsize, size_t nmemb, size_t size, size_t alignment, size_t *bytes_to_take)
{
    assert(mem != NULL);
    assert(nmemb != 0); // we can't "free"
    assert(size != 0);
    assert(alignment != 0);

    // get array size
    const size_t s = nmemb * size;
    if (nmemb != 0 && s / nmemb != size) {
        // overflow!
        return NULL;
    }

    // align
    const size_t rest = (size_t)((uintptr_t)*mem % alignment);
    const size_t alignmentadd = rest == 0 ? 0 : alignment - rest;
    // fprintf(stderr, "alignment %d %d %d %d\n", alignmentadd, ((uintptr_t)*mem % alignment), *memsize, s);

    // inform of bytes we need to take
    if (bytes_to_take != NULL) {
        *bytes_to_take = alignmentadd + s;
    }

    // check free memory
    if (*memsize < alignmentadd + s) {
        //fprintf(stderr, "ENOMEM %d %d %d \n", *memsize, alignmentadd, s);
        // ENOMEM!
        return NULL;
    }

    // update state, get s + alignmentadd bytes, return ret
    char *memc = *mem;
    memc += alignmentadd;
    void * const ret = memc;
    memc += s;
    *mem = memc;
    *memsize -= alignmentadd + s;

    return ret;
}

int main()
{
    #define SOME_SIZE  (sizeof(float) * 2 + 3 * sizeof(double) + 8)
    char mem[SOME_SIZE];
    void *mem_pos = mem;
    size_t memsize = sizeof(mem);

    float  *f = mem_take(&mem_pos, &memsize, 2, sizeof(float), 8, NULL); // 2 floats
    assert(f != NULL);
    double *d = mem_take(&mem_pos, &memsize, 3, sizeof(double), 8, NULL); // 3 doubles
    assert(d != NULL);
    // etc.

    // now free to use the memory via arrays
    f[0] = 1.0f;
    f[1] = 2.0f;

    d[0] = 1.0f;
    d[1] = 2.0f;
    d[2] = 3.0f;

    printf("%f %f %lf %lf %lf\n", f[0], f[1], d[0], d[1], d[2]);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 2011-01-16
    • 1970-01-01
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多