简体   繁体   English

C:指向malloc的堆位置的指针加4

[英]C: pointer to malloc'ed heap location plus 4

I'm trying to implement a new malloc that stores the size at the front of the malloc'ed region, and then returns a pointer to the incremented location (what comes after the stored unsigned int). 我正在尝试实现一个新的malloc,该大小将大小存储在malloc的区域的前端,然后返回一个指向递增位置的指针(在存储的unsigned int之后出现)。

void* malloc_new(unsigned size) {
    void* result = malloc(size + sizeof(unsigned));
    ((unsigned*)result)[0] = size;
    result += sizeof(unsigned);
    return result;
}

I'm having doubts regarding whether the 我对是否

result += sizeof(unsigned);

line is correct (does what I want). 行是正确的(做我想要的)。 Say the original address in the heap for the malloc is X, and the size of unsigned is 4, I want the 'result' pointer to point to X + 4, right? 假设堆中malloc的原始地址为X,而unsigned的大小为4,我希望“结果”指针指向X + 4,对吗? Meaning that the memory location in the stack that stores the 'result' pointer should contain (the original heap address location + 4). 意味着堆栈中用于存储“结果”指针的内存位置应包含(原始堆地址的位置+ 4)。

result += sizeof(unsigned); should give you at least a warning (pointer arithmetic on void * leads to undefined behavior). 应该至少给您一个警告(对void *指针运算会导致未定义的行为)。

unsigned *result = malloc(size + sizeof size);
result[0] = size;
return result + 1;

should be the easier way. 应该是更简单的方法。

Please note that the returned memory is not well aligned for all possible datatypes. 请注意,对于所有可能的数据类型,返回的内存未完全对齐。 You will run into troubles if you are using this memory for double or other 64bit datatypes. 如果将此内存用于double精度或其他64位数据类型,则会遇到麻烦。 You should use an 8 byte datatype uint64_t for storing the size, then the memory block afterwards is well aligned. 您应该使用8字节数据类型uint64_t来存储大小,然后将内存块对齐。

In addition to the problems noted in other answers with performing pointer arithmetic on void * pointers, you're also likely violating one of the restrictions the C standard places on memory returned from functions such as malloc() . 除了在其他答案中对void *指针执行指针算术所指出的问题之外,您还可能违反了C标准对从诸如malloc()函数返回的内存上的限制之一。

7.22.3 Memory management functions , paragraph 1 of the C standard states: 7.22.3内存管理功能 ,C标准的第1段规定:

The order and contiguity of storage allocated by successive calls to the aligned_alloc , calloc , malloc , and realloc functions is unspecified. 未指定连续调用对aligned_alloccallocmallocrealloc函数分配的存储的顺序和连续性。 The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). 如果分配成功,则返回的指针将进行适当对齐,以便可以将其分配给具有基本对齐要求的任何类型的对象的指针,然后将其用于在分配的空间中访问此类对象或此类对象的数组 (直到空间已明确释放)。 The lifetime of an allocated object extends from the allocation until the deallocation. 分配对象的生命周期从分配一直到释放为止。 Each such allocation shall yield a pointer to an object disjoint from any other object. 每个这样的分配都应产生一个指向与任何其他对象不相交的对象的指针。 The pointer returned points to the start (lowest byte address) of the allocated space. 返回的指针指向分配空间的开始(最低字节地址)。 If the space cannot be allocated, a null pointer is returned. 如果无法分配空间,则返回空指针。 If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object. 如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为类似于该大小为某个非零值,不同之处在于不得使用返回的指针访问对象。

Note the bolded part. 请注意粗体部分。

Unless your system has a fundamental alignment that's only four bytes (8 or 16 is much more typical), you are violating that restriction, and wil invoke undefined behavior per 6.3.2.3 Pointers , paragraph 7 for any object type with a fundamental alignment requirement larger than four bytes: 除非您的系统的基本对齐方式只有四个字节(通常为8或16个字节),否则您将违反该限制,并且会针对任何具有基本对齐方式要求较大的对象类型,按照6.3.2.3指针第7段的规定调用未定义的行为。超过四个字节:

... If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...如果结果指针未针对引用类型正确对齐,则行为未定义。 ... ...

How void pointer arithmetic is happening in GCC 空指针算法在GCC中如何发生

C does not allow pointer arithmetic with void * pointer type. C不允许使用void *指针类型的指针算术。

GNU C allows it by considering the size of void is 1 . GNU C通过考虑void的大小为1允许它。

The result is void* so result += sizeof(unsigned); resultvoid*因此result += sizeof(unsigned); just happens to work on compatible compilers. 恰好在兼容的编译器上工作。

You can refactor your function into: 您可以将函数重构为:

void *malloc_new(unsigned size) {
    void* result = malloc(size + sizeof(unsigned));
    ((unsigned*)result)[0] = size;
    result = (char*)result + sizeof(unsigned);
    return result;
}

Side note, before void type and void* generic pointer existed in the C language, programmers used char* to represent a generic pointer. 附带说明,在C语言中存在void类型和void*通用指针之前,程序员使用char*表示通用指针。

You can do void* arithmetic if you cast the type first to char*, for instance. 例如,如果将类型首先转换为char *,则可以执行void *算术运算 And then cast back to void*. 然后投射回void *。 To get better alignment, use 64 bit type for the size, eg uint64_t . 为了更好地对齐,请使用64位类型作为大小,例如uint64_t

#define W_REF_VOID_PTR(ptr,offset) \
    ((void*)((char*) (ptr) + (offset)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM