Create a readonly pointer argument of any type in C

163 Views Asked by At

I want to make a macro that when given a type T, will return a pointer type that is readonly when passed to a function, like so:

void foo( readonly_ptr(char) str )
{
    // can only read from str, not modify it
}

This proved to be harder than I thought, since simply prepending const isn't enough.

My current code is:

#define readonly_ptr(T) \
const typeof(T)*

Which works for "simple" types.

But doesn't work with all types.

When given a pointer-to-array type (e.g. int(*)[10]) it turns it into int(*const*)[10] which still allows the function to modify the array like this:

void foo( readonly_ptr(int(*)[10]) arr )
{
    (**arr)[0] = 1;
}

Similarly for pointer types (e.g. char*) it turns it into char *const* which can have its underlying chars modified.

Is there a way to make a macro that guarantees a readonly parameter?

If not, is there another way to make sure a function won't modify the argument, without having to specify the exact type every single time.

I also tried always passing const void* every time I needed a readonly, however that is still legally cast-able to a modifiable type.

2

There are 2 best solutions below

0
On BEST ANSWER

I guess if your underlying question is whether it is possible to make the memory location immutable in every case the answer is probably no. I don't think there is a way to make something 100% read-only when pointers are involved with a Makro like this.

  • If not, is there another way to make sure a function won't modify the argument, without having to specify the exact type every single time?

This might differ between C standards, compilers and systems, but casting away const and modifying the value should be undefined behavior. Check out this link. Some systems might just segfault, others will probably work if you try to hack your way around const with casting. So this will be difficult.

If you want to make this pointer-shenanigans at least somewhat difficult, how about creating some API. You could try to pass a function, that does the reading on a memory location you defined before you call foo. Then again, you could just copy and afterwards pass it.

0
On

C declaration syntax, especially with respect to pointers, is too rich for such a simple macro to be possible.

As you have discovered, it doesn't work for pointers to arrays, pointers to functions, and it won't work for pointers to pointers either.

If you're passing a pointer to an array and you want to make sure individual array elements are const, you'll have to do it the hard way:

void foo( const T (*arr)[N] ); // or T const (*arr)[N]