取malloc()、realloc()和free()的地址是否可移植?

Is it portable to take the address of malloc(), realloc() and free()?

根据标准,使用 malloc()realloc()free() 的地址安全吗?

例如,

#include <stdlib.h>
void * (*my_malloc)(size_t) = &malloc;

推论,在符合标准的 C 中,实现是否可能使用 malloc/realloc/free 的宏?

是的,这是安全的。允许标准库为其任何函数定义 function-like 宏,但它们也必须作为函数可用。

C17 7.1.4 (1)

Any function declared in a header may be additionally implemented as a function-like macro defined in the header, so if a library function is declared explicitly when its header is included, one of the techniques shown below can be used to ensure the declaration is not affected by such a macro. Any macro definition of a function can be suppressed locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. For the same syntactic reason, it is permitted to take the address of a library function even if it is also defined as a macro. [189]

[189] This means that an implementation shall provide an actual function for each library function, even if it also provides a macro for that function.

所以简而言之,图书馆的 header 允许有类似

的内容
void *malloc(size_t);
#define malloc(s) __fancy_internal_malloc((s) + 47 | 0x14 * 3)

然后你可以做任何

void *p = malloc(10); // invokes the macro if there is one
void *q = (malloc)(10); // definitely calls the function, not the macro
void *(*allocator)(size_t) = &malloc; // takes address of the function
#undef malloc
void *r = malloc(10); // definitely the function

当然,函数和宏都必须提供标准承诺的任何行为(尽管正如 Eric Postpischil 评论的那样,只要它们符合标准,它们的行为就不必相同)。特别是,使用宏分配和使用函数释放必须是安全的,反之亦然。此外,这样的宏必须对它的每个参数只计算一次,因此 p = malloc(s++); 对于函数或宏都是安全的。