简体   繁体   中英

Combination of macros behaving unusually

Following the advice of Reese's Understanding and Using C Pointers , I defined a 'safe free' combination of function and macro, as follows:

#define safeFree(p) saferFree((void*)&(p))

void saferFree(void **pp) {
    if (pp !=NULL && *pp !=NULL) {
        free(*pp);
        *pp = NULL;
    }
}

Then, following the advice of Klawonn's 21st Century C , I also defined the 'apply to list' macro as follows:

#define Fn_apply(type, fn, ...) {    \
    void *stopper_for_apply = (int[]){0};    \
    type **list_for_apply = (type*[]){__VA_ARGS__, stopper_for_apply};    \
    for (int i = 0; list_for_apply[i] != stopper_for_apply; i++) {    \
        fn(list_for_apply[i]);    \
    }    \

These are both defined in one file. Then, in another file (which includes these), I have a struct, which contains an internal array which is dynamically allocated. Now, I've defined a custom deallocation function for this struct, which looks roughly like this:

void deallocate (S** s_ptr) {
    safeFree((*s_ptr)->arr); //deallocates the array
    safeFree(*s_ptr); //deallocates the struct
}

Now, I've tested it with the following code:

S* foo = allocate(); //allocates a new struct, makes the internal array as well
deallocate(&foo);
assert(!foo);

With the above deallocate , this passes. However, if I change deallocate to this:

void deallocate (S** s_ptr) {
    Fn_apply(void, safeFree, (*s_ptr)->arr, *s_ptr);
}

The memory gets removed fine, but the assertion above fails. Did I miss something?

I created this compilable code from your question:

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

typedef struct S
{
    int *arr;
} S;

#define safeFree(p) saferFree((void *) & (p))

extern S *allocate(void);
extern void saferFree(void **p);
extern void deallocate(S **s_ptr);
extern void deallocate2(S **s_ptr);
extern void function(void);

void saferFree(void **pp)
{
    if (pp != NULL && *pp != NULL)
    {
        free(*pp);
        *pp = NULL;
    }
}

#define Fn_apply(type, fn, ...) {    \
        void *stopper_for_apply = (int[]){0};    \
        type **list_for_apply = (type *[]){__VA_ARGS__, stopper_for_apply};    \
        for (int i = 0; list_for_apply[i] != stopper_for_apply; i++) {    \
            fn(list_for_apply[i]);    \
        } }

void deallocate(S **s_ptr)
{
    safeFree((*s_ptr)->arr); // deallocates the array
    safeFree(*s_ptr); // deallocates the struct
}

void function(void)
{
    S *foo = allocate(); // allocates a new struct, makes the internal array as well
    deallocate(&foo);
    assert(!foo);
}

void deallocate2(S **s_ptr)
{
    Fn_apply(void, safeFree, (*s_ptr)->arr, *s_ptr);
}

I ran the preprocessor on it, and then formatted the section from the structure definition onwards. That gives:

typedef struct S
{
    int *arr;
} S;


extern S *allocate(void);
extern void saferFree(void **p);
extern void deallocate(S **s_ptr);
extern void deallocate2(S **s_ptr);
extern void function(void);

void saferFree(void **pp)
{
    if (pp != ((void *)0) && *pp != ((void *)0))
    {
        free(*pp);
        *pp = ((void *)0);
    }
}

# 33 "fz.c"
void deallocate(S **s_ptr)
{
    saferFree((void *) &((*s_ptr)->arr));
    saferFree((void *) &(*s_ptr));
}

void function(void)
{
    S *foo = allocate();
    deallocate(&foo);
    (__builtin_expect(!(!foo), 0) ? __assert_rtn(__func__, "fz.c", 43, "!foo") : (void)0);
}

void deallocate2(S **s_ptr)
{
    {
        void *stopper_for_apply = (int[]){0};
        void **list_for_apply = (void *[]){
            (*s_ptr)->arr, *s_ptr, stopper_for_apply
        };
        for (int i = 0; list_for_apply[i] != stopper_for_apply; i++)
        {
            saferFree((void *) &(list_for_apply[i]));
        }
    }
}

This code confused Uncrustify 0.60 into producing uncompilable code; it botched the formatting of the two array literals, losing the trailing semicolons.

I think the output shows the problem. You're working with copies of the (*s_ptr)->arr and *s_ptr in the list_for_apply array, rather than the originals. So, the two lots of code simply make different assumptions about what's going on, and therefore come to the wrong conclusion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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