如何使用可移植的方式检查malloc
是否未成功分配非零内存块?
我总是这样做:
tok = malloc( sizeof( char ) * ( strlen(tc) + 1 ) );
if( tok == NULL )
{
/* Malloc failed, deal with it */
}
有些人会写成 tok = (type) malloc( ... )
但你应该强制转换结果,因为这样可以隐藏一些难以发现的错误。我将进行一些研究,看看能否找出确切的错误。
编辑:
强制转换malloc会隐藏掉一个遗漏的#include <stdlib.h>
我在这个链接中找到了一个非常好的解释:
http://cboard.cprogramming.com/faq-board/25799-faq-casting-malloc.html
"所以当你这么写(char*)malloc(10)
你是说你拿到malloc返回的任何东西, 把它转换成char*, 并将其分配给相关变量。
如果malloc被适当地声明(通过包含stdlib.h), 其定义返回void*,这一切都很好。
问题出在你没有包含stdlib.h时, 编译器最初假设malloc返回int。 真正的问题是,你没有从编译器获得任何警告。
然后你高高兴兴地把那个int转换成了char* (通过强制类型转换)。 在sizeof(char*)与sizeof(int)不同的机器上, 这段代码是严重错误的。
现在,如果你只是写 char *var = malloc(10); 而忘记了包含头文件, 编译器会给出警告。"
sizeof(char)
гЂ‚еЏҮд»ӨдҢүз”Ёsizeof *tok
жқӨд»Әж›үпәЊж€–者干脆дёҚ写。 - R.. GitHub STOP HELPING ICEchar
,而 sizeof
是以 char 为单位的。根据定义,sizeof(char)
为1,从概念上讲,这类似于单位误差。无论如何,使用 sizeof *dest_ptr
更好,因为如果您将 dest_ptr
(此处为 tok
)的类型更改为其他类型,它会自动调整。 - R.. GitHub STOP HELPING ICEint
,需要乘以sizeof(int)
。但是,直接从指向类型大小中获取大小最安全,例如在你的示例中使用sizeof *tok
。这样,如果更改类型并忘记更新malloc
调用,就不会传递错误的大小。 - R.. GitHub STOP HELPING ICEmalloc(n)
返回NULL
errno
。如果您需要详细信息,例如记录日志,我会在调用之前将errno
设置为0,看看它是否更改,然后可能记录下来。
malloc(n)
返回一个非NULL
地址,该地址没有被实际内存支持read()
从一个随机文件读取到测试区域并查看操作系统是否返回EINVAL或等效值。malloc(0)
返回NULL
,并使errno
未定义NULL
(可以这样做),但然后失败,因此必须返回NULL
。它可以尝试设置errno
。这是一个失败吗?我认为Hoare说我们为这种歧义付出了十亿美元。因此,调用malloc(0)
是不可移植的,而提问者可能已经知道了! malloc(...)
是否返回NULL
。malloc(n)
在失败时返回NULL
。
malloc(0)
可能会返回NULL
。
为了检测失败:
void* ptr = malloc(n);
if (ptr == NULL && n > 0) Handle_Failure();
注意:
就像在提问者的情况中:“……分配非零内存块”,通常代码是这样的,即不能出现0
的分配请求,因此不需要进行0
测试。
size_t nstr = strlen(some_string) + 1;
void* ptrstr = malloc(nstr);
if (ptrstr == NULL) Handle_Failure();
一些系统在失败时会设置errno
,但并非所有系统都是这样。在C11规范中,由于内存分配失败而设置errno
是没有明确定义的。
malloc(n)
函数期望的参数n
是无符号类型size_t
。如果使用带有负值的int n
,将转换为一些较大的无符号值,然后可能会导致内存分配失败。
errno
是线程安全的。不要听信告诉你相反的人。 - R.. GitHub STOP HELPING ICEmalloc()
在分配失败时会返回NULL
。即使 OP 使用 "分配非零内存块" 进行了豁免,malloc(0)
也可能返回NULL
。 - chux - Reinstate Monicamalloc()
失败时设置errno
,因此一般情况下不能依赖它。 - Toby Speight