是否可以释放在 printf 内部调用的函数(仅)的返回值(在 c 中)?

Is it possible to free the returned value of a function (only) called inside of printf (in c)?

假设我正在编写一个类似 strdup() 的函数,或者任何其他使用 malloc() 的函数。如果我只像这样在 printf() 内部调用此函数:

printf("%s", my_function(arg));

是否可以释放函数返回的值?如果是,如何?据我所知,free() 将一个空指针作为参数,但如果您从不将返回值存储在变量中,您如何获得该指针?

否 - 您需要将其命名为:

char *p;

p = my_function(arg);
printf("%s", p);
free(p);

编辑

如果你喜欢代码滥用,你可以这样做:

for(char *p = my_function(arg); p != NULL ; free(p), p = NULL)
  printf("%s", p);

但这太可怕了...

Is it possible to free the returned value of a function (only) called inside of printf (in c)?

没有


备选方案:使用复合文字“分配”。

而不是在 my_function(char *arg) 中分配,确定所需的大小并将 复合文字 传递给 my_function(char *arg, char *buf),然后 returns buf.

如果最大大小不是太大,则不在 my_function(char *arg) 中分配,而是将 复合文字 传递给 my_function(char *arg, char *buf),然后 [=44] =] buf.

#define MY_FUNCTION_SIZE 42
printf("%s", my_function(arg, char [MY_FUNCTION_SIZE]{0}));

复合文字在代码块结束前有效。然后它是“未分配的”。 malloc()free() 也不需要明确命名的临时对象。

Example.

嗯....您可以执行以下操作(保存指针以供以后处理,例如 free()ing 它)

char *p;
printf("%s", p = my_function(arg));
free(p);

或者,更易读

void *p = my_function(arg);
printf("%s", p);
free(p);

第二种方法是设计my_function()在预先分配的(稍后解释)缓冲区上运行。

char *my_function(some_type arg, char *buffer, size_t buff_sz)
{
    /* use buffer as a work buffer */
    /* ... */
    return buffer;
}

然后将它与一些缓冲区一起使用,分配在 auto 变量中:

    if (something) {
        char buffer[1000];
        printf("%s", my_function(arg, buffer, sizeof buffer));
    }
    /* buffer is gone here */

这是一种非常灵活的工作方式,一旦你掌握了它。

一旦我编写了一个例程,将一系列分配的指针保存到 free()(或者可能 post 处理指针),一旦工作完成,它们就会全部保存。为了允许像你提出的那样的表达式,函数采用一个指针(分配的指针)并将其保存在一个结构中,函数返回它的参数,所以上面的构造是可能的

它仅由一个头文件和一个包含两个函数的简单文件组成:

  1. mf_save(),保存一个指针供以后释放。
  2. mf_free(),到 post-处理(并释放)一次性保存的所有指针。此例程还 free() 分配了用于保存指针的内存,因此 post 处理仅完成一次,之后所有保存的指针都将丢失,因此您最好 free() 它们在您传递给它的 post-processing 例程指针。一个常见的使用它来传递它只是 free.

mf.h

/* mf.h -- types and definitions for mf.c.
 * Author: Luis Colorado <luiscoloradourcola@gmail.com>
 * Date: Sun Sep 19 12:16:18 EEST 2021
 * Copyright: (c) 1992-2021 Luis Colorado.  All rights reserved.
 * License: BSD.
 */
#ifndef _MF_H
#define _MF_H

#define MF_F(_fmt) "%s:%d:%s: "_fmt, __FILE__, __LINE__, __func__

typedef struct mf_s *mf_t;

void *mf_save(mf_t *safe_ref, void *ptr);

void  mf_free(mf_t *safe_ref, void (*proc)(void *));

#endif /* _MF_H */

mf.c

这是模块的核心。

/* mf.c -- a module to save pointers for batch free()ing, after
 * work is done.
 * Author: Luis Colorado <luiscoloradourcola@gmail.com>
 * Date: Sun Sep 19 11:54:37 EEST 2021
 * Copyright: (c) 1992-2021 Luis Colorado.  All rights reserved.
 * License: BSD.
 */

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

#include "mf.h"

#define MF_SIZE     (3)
#define THIS    (*safe_ref)

struct mf_s {
    size_t  mf_n;           /* num of saved in this block */
    mf_t    mf_nxt;         /* nxt chunk pointer */
    mf_t    mf_vec[MF_SIZE];/* saved pointers */
};

static mf_t
mf_alloc(mf_t prev)
{
    /* call calloc, so the block is zeroed */
    mf_t ret_val = calloc(1, sizeof * ret_val);
    assert(ret_val != NULL);
    ret_val->mf_nxt = prev;
    return ret_val;
}

void *
mf_save(mf_t *safe_ref, void *ptr)
{
    if (THIS == NULL || THIS->mf_n == MF_SIZE) { /* full chunk */
        printf(MF_F("full chunk, allocating new [%p]"), THIS);
        THIS = mf_alloc(THIS);
        printf(" -> [%p]\n", THIS);
    }
    mf_t s = THIS;
    s->mf_vec[s->mf_n++] = ptr;
    printf(MF_F("SAVED [%p]\n"), ptr);
    return ptr;
}

void
mf_free(mf_t *safe_ref, void (*proc)(void *))
{
    while(THIS) {
        int ix;
        for (ix = 0; ix < THIS->mf_n; ++ix) {
            void *p = THIS->mf_vec[ix];
            printf(MF_F("processing [%p]\n"), p);
            proc(p);
        }
        mf_t temp = THIS;
        THIS = THIS->mf_nxt;
        printf(MF_F("freeing chunk @ [%p] -> [%p]\n"), temp, THIS);
        free(temp);
    }
}

这种方法的好消息是它只使用动态内存,而且保险箱只占用堆栈中指针的大小。另一个好的想法是它是 1992 年编写的,因此它不需要任何编译器新奇。


test_mf.c

这是一个测试例程,它分配 10 个指针(随机大小,但使用 space 将分配的大小存储在其中 --- 其余未使用)然后通过调用 [=23] 释放它们=].

#include <stdio.h>
#include <stdlib.h>

#include "mf.h"

/* this is a wrapper to malloc() to store the number of bytes in
 * the allocated memory, so the processing() routine has the
 * possibility of printing the amount of allocated memory */
static void *
malloc_wrapper(size_t n)
{
    int *ret_val = malloc(n);
    printf(MF_F("allocated %zd bytes @ %p\n"), n, ret_val);
    *ret_val = n;
    return ret_val;
}

/* this is a wrapper to free() to printf the number of allocated
 * bytes that are being freed. */
void
free_wrapper(void *p)
{
    int *q = p;
    printf(MF_F("freeing %d bytes @ %p\n"), *q, p);
    free(p);
}

/* main program, allocate 1000 random sized buckets of memory,
 * then deallocate them. */
int
main()
{
    int i;
    mf_t safe = NULL; /* initialize to NULL always */
    for (i = 0; i < 10; i++) { /* several allocations */
        int size = rand() & 1000 + sizeof(int);
        printf("Allocating %d bytes @ %p\n", size, mf_save(&safe, malloc_wrapper(size)));
    }
    /* all are freed at the end of the work */
    mf_free(&safe, free_wrapper);
}

(注意:我已经为 malloc()free() 编写了包装器以在内存量 allocated/deallocated 上插入跟踪,但您可以使用 malloc()free() 在他们的位置。)


生成文件

Makefile 允许您构建测试程序。

targets     = test_mf

test_mf_objs = test_mf.o mf.o
to_clean = test_mf $(test_mf_objs)

all: $(targets)
clean:
        $(RM) $(toclean)

test_mf: $(test_mf_deps) $(test_mf_objs)
        $(CC) $(CFLAGS) $(LDFLAGS) $($@_ldfl) -o $@ $($@_objs) $($@_libs)

此处的例程受版权保护,但您可以在 BSD 许可下自由使用它们。