1

Context

I have some functions to support using a custom memory allocator in my library:

void *(allocate)(struct allocator *allocator, size_t size, size_t alignment);
void (deallocate)(struct allocator *allocator, void *pointer, size_t size, size_t alignment);

There's two things that I would still like to improve upon with this interface:

  1. There is a need to write sizeof(type) and alignof(type) for every allocation and deallocation.
  2. The type void * allows mistakenly using a pointer to a type with invalid size or alignment.

Both of these can be fixed with some simple macros:

#define allocate(allocator, type, count) \
    (type *)(allocate)(allocator, sizeof(type) * (count), alignof(type))

#define deallocate(allocator, pointer, type, count) \
    do { \
        type *typed_pointer = pointer; \
        (deallocate)(allocator, typed_pointer, sizeof(type) * (count), alignof(type)); \
    } while (0)

The macro takes care of calling sizeof(type) and alignof(type), and also performs a cast of the pointer to the given type so the compiler issues a warning when it is used as a different type.

Problem

deallocate does not have a return value, so we can implement it as a block with a variable to perform the implicit pointer cast. But for a function that does return a value, maybe reallocate, we cannot type check the pointer that is passed to the macro in the same way.

Is there any way to perform this "type checking" implicit cast inline inside of an expression, such that the macro can have a result?

EDIT: I would like to stick to standard C without any GNU or other extensions, if possible.

7
  • You mean like gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html? Commented Jun 27, 2024 at 21:18
  • 1
    Frame challenge: the deallocator shouldn't need to be told the size/alignment of the pointed-to memory. It should keep track of that itself. free doesn't need to be given that information. Commented Jun 27, 2024 at 21:18
  • The only "type" checking needed with reallocate() is the alignment. Allocate in such a way that given a pointer from this (re)allocate() can recover the used alignment and then check that on reallocate(). Commented Jun 27, 2024 at 21:19
  • @dbush Agree about lack of need for size/alignment yet passing them on deallocation allows for interesting/useful checks. Commented Jun 27, 2024 at 21:22
  • @CarlNorum Yeah, that would work, but I would like to stick to standard C without any extensions, if possible. Commented Jun 27, 2024 at 21:27

1 Answer 1

1

You can use a compound literal, (type *) { pointer } as the argument to reallocate, and the compiler will do its usual checks for assignment to a pointer type. Per C 2018 6.5.2.5 2 and 6, the constraints and semantic rules for an initializer list apply to a compound literal, and per 6.7.9 11, the constraints and semantic rules for assignment apply to an initializer for a scalar, except that the type is taken to be unqualified.

Not all types can be handled this way, as appending *to a type does not necessarily yield a pointer to that type. For example, int [] would produce int [] *, which will not work. You already have that problem for the (type *) cast on allocate. The user could use a typedef for any type, though, and then pass the typedef name.

Sign up to request clarification or add additional context in comments.

6 Comments

TIL compound literals are lvalues.
@DutChen18, That's the whole point. Otherwise, we could use constants.
@ikegami: Maybe 80% of the point. Maybe less. Compound literals are useful for constructing structure values, which is nice for assigning to structure variables. That may be the majority of what I have used them for in production code.
@Eric Postpischil, How is it better than an initializer (struct Foo foo = { ... };)?
Or just (type*){ pointer } which is equivalent. Initialization is done "as per assignment", so the same type compatibility check is performed either way.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.