C 传递给free()的指针必须指向内存块的开头,还是可以指向内存块的内部?

C 传递给free()的指针必须指向内存块的开头,还是可以指向内存块的内部?,c,memory-management,free,calloc,C,Memory Management,Free,Calloc,问题在标题中。。。我搜索了一下,但什么也没找到 编辑: 我真的不认为有必要解释这一点,但因为人们认为我所说的毫无意义(而且我问的问题是错误的),所以问题出在这里: 由于人们似乎对所有问题的“根本”原因非常感兴趣,而不是实际问题(因为这显然有助于更好地解决问题,让我们看看它是否有帮助),问题是: 我正在尝试基于NTDLL.dll创建一个D运行时库,这样我就可以将该库用于Win32子系统以外的子系统。因此,这迫使我只能链接到NTDLL.dll 是的,我知道这些函数是“未记录”的,并且随时可能发生变

问题在标题中。。。我搜索了一下,但什么也没找到


编辑:

我真的不认为有必要解释这一点,但因为人们认为我所说的毫无意义(而且我问的问题是错误的),所以问题出在这里:

由于人们似乎对所有问题的“根本”原因非常感兴趣,而不是实际问题(因为这显然有助于更好地解决问题,让我们看看它是否有帮助),问题是:

我正在尝试基于NTDLL.dll创建一个D运行时库,这样我就可以将该库用于Win32子系统以外的子系统。因此,这迫使我只能链接到NTDLL.dll

是的,我知道这些函数是“未记录”的,并且随时可能发生变化(尽管我敢打赌,
wcstombs
在20年后仍然会做同样的事情,如果它仍然存在的话)。是的,我知道人们(尤其是微软)不喜欢开发人员链接到这个库,我可能会因为这个问题而受到批评。是的,上面这两点意味着在Win32子系统之前运行的chkdsk和碎片整理程序根本不应该被创建,因为根本不可能链接到像kernel32.dll或msvcrt.dll这样的任何东西,并且仍然有NT本机可执行文件,因此,我们开发人员应该假装这些阶段意味着永远超出我们的能力范围

但不,我怀疑这里是否有人希望我粘贴几千行代码,并帮助我查看它们,并试图找出为什么没有失败的内存分配会被我正在修改的源代码拒绝。所以这就是为什么我问了一个不同于“根本”原因的问题,尽管这被认为是社区的最佳实践

如果事情仍然没有意义,请随时在下面发表评论!:)


编辑2:

经过大约8小时的调试,我终于发现了问题:


事实证明,
RtlReAllocateHeap()
不会像
RtlAllocateHeap()
那样自动工作,如果给它的指针是
NULL
它必须指向块的开头。将空指针传递到
free()
是安全的,但传递任何未由
malloc()
或其亲属分配的指针将导致未定义的行为。有些系统会给你一个运行时错误——类似于“指针的释放而不是malloced”

编辑:

我编写了一个测试程序来获取错误消息。在我的机器上,此程序:

#include <stdlib.h>

int main(int argc, char **argv)
{
  int *x = malloc(12);
  x++;

  free(x);

  return 0;
}

您可以传递给
free
唯一对象是从
malloc
返回给您的指针(或
calloc
realloc
等),或NULL


我猜你这么问是因为你有一个函数,在这个函数中你做了一个malloc,你想弄乱数据块,然后在完成后把它处理掉,你不想麻烦保留一个原始指针的副本。这样不行。

从您在现有答案中添加的评论来看,似乎您提出了错误的问题。如果你需要的是内存对齐,为什么不问这个问题呢?询问根本问题,而不是询问您的解决方案

如果你不介意的话,我会回答你应该问的问题:

Win32中支持对齐的内存分配。它与POSIX
memalign()

如果您需要对齐分配的实现,那么实现起来相当简单:

void* aligned_malloc( size_t size, size_t alignment )
{
    void* unaligned = malloc( size + alignment ) ;
    void* aligned = (void*)(((intptr_t)unaligned + alignment) & ~(alignment - 1));
    void** free_rec_ptr = ((void**)aligned - 1) ;
    *free_rec_ptr = unaligned ;

    return aligned ;
}

void aligned_free( void* block )
{
    void** free_rec_ptr = ((void**)block - 1) ;
    free( *free_rec_ptr ) ;
}

alignment
参数必须是二的幂。

FWIW,上次我研究C运行时库如何与
malloc
free
一起工作时,
malloc
提供给您的块实际上在相对于指针的负偏移处有一些额外的字。比如说街区有多大等等<代码>免费依赖于能够找到这些东西。我不知道这会不会让人觉得轻松。

嗯。。。那么在这种情况下,有没有一种方法可以(可移植地)请求64字节对齐的内存呢?我本来打算分配更多数据并提取一个片段,但由于我在传递指针,我无法在开始时跟踪未使用字节的大小…@Lambert,你当然可以。写“对齐的malloc”实际上是一个非常流行的求职面试问题。只需为对齐分配足够的空间,并为指针分配额外的空间。然后将指针隐藏在对齐内存的正前方,编写一个
free()
函数,将此信息提取出来并释放“真实”指针。这并不是我不能,而是我必须创建一个全新的表并跟踪其中的内容。。。虽然我知道怎么做,但如果可以的话,我想避免的只是疼痛没那么难。但您也可以使用
memalign()
和friends。看看这个答案:“应该给你一个运行时错误”不是必需的行为;结果未定义且依赖于实现。在某些情况下,它只会通过添加一个无效的块来破坏堆,您可能不会注意到,直到后续的内存分配发生时,当sh*t发生时!哈哈,并不是我不想麻烦,而是在我的情况下要做到这一点并不容易。但谢谢你的回答。:)怎么不容易做到呢?您正在调用某个API函数,而该函数不会将
malloc
ed指针返回给您吗?如果它具体地隐藏了它,那么您应该让API函数来进行内存管理。要小心,因为双重释放bug非常烦人,因为你必须弄清楚是谁先释放的,以及为什么。哈哈哈,不,我正在尝试在NTDLL的上面实现一个对齐的malloc
void* aligned_malloc( size_t size, size_t alignment )
{
    void* unaligned = malloc( size + alignment ) ;
    void* aligned = (void*)(((intptr_t)unaligned + alignment) & ~(alignment - 1));
    void** free_rec_ptr = ((void**)aligned - 1) ;
    *free_rec_ptr = unaligned ;

    return aligned ;
}

void aligned_free( void* block )
{
    void** free_rec_ptr = ((void**)block - 1) ;
    free( *free_rec_ptr ) ;
}