Nice try, but:
* As you have it, Image_t is now not so opaque; you've introduced a struct
and a pointer
If it's not opaque, how many members does it have? What are their names
and types, and in what order are they allocated? Keep in mind that no
more information need be given to the compiler, than I've already given
you, in order to write code that passes around Image_t* values. The fact
that I've used a struct is not something the user needs to know about -
it could just as easily have been a union or an arithmetic type (though
it would have to be a pretty small image to fit in a single object of a
standard arithmetic type - a long double _Complex would typically not be
large enough for anything more than a 16x10 b/w image).
If you need more opacity than that, you'll have to explain why. Hiding
the fact that it's a pointer behind a typedef is TOO MUCH opacity,
because it can cause things to be syntax errors that don't look like
syntax errors (and vice versa). If you want to use an array type, you
can store it inside the struct. Making Image_t itself an array type
would cause it to be unexpectedly treated as a pointer in some contexts.
* As written, the const here doesn't stop SomeFunction from changing the
image data (it might make it harder to change details in the descriptor,
*if* implemented as a pointer to a struct).
As written, it is a pointer to a struct, and therefore requires
SomeFunction() to cast away the 'const' in order to change the value of
any member of that struct. I always treat casts with suspicion, as
something that should be avoided, so that's sufficient to be useful
(though I'd prefer a new language feature that would cause such casts to
be constraint violations).
This approach can't do anything about structs that contain pointers to
the actual data managed by the struct, or indices into arrays that are
not part of the struct. That reduces the value of using 'const' for this
purpose, but it does not eliminate that value - it doesn't even come
close to doing so. Rather, it reduces (but does not eliminate) the value
of using such structures for managing the data.
I suppose you could consider this 'const' to be just a token, informal way
of telling a human reader that it will not modify the image data. But in
that case a comment would do just as well.
For the purposes of my response, consider:
someotherreturntype SomeOtherFunction(Image_t *);
A comment in place of the 'const' in the declaration of SomeFunction()
would not cause a mandatory diagnostic if SomeFunction() attempts to
modify the object pointed at, including, as a special case, any attempt
to pass that pointer to SomeOtherFunction(). Therefore, a comment is not
an adequate substitute for 'const'.