That's a possible method to provide encapsulation, but it does nothing
to address the existing issue of involuntary ABI ossification. I would
consider this to be an implementation detail that can be left to whoever
is implementing a public interface.
It creates a clear divide between the shared ABI and the static ABI. Things like this are possible for example:
inline ssize_t read( int fd, void *dest, size_t size )
{
int res = stdiocall( fd, STDCALL_FETCH, dest, &size );
errno = (res < INT_MIN || res > INT_MIN) ? -1 : res;
return (res != 0) ? -1 : size;
}
#ifdef EXTERN_STD_INLINES
extern ssize_t read( int fd, void *dest, size_t size );
#endif
To enable this sort of thing would have to swap the errno usage I gave in the previous example for a separate errno, like errno32 for example.
Since errno32 would be a fixed size it can still be exposed to the public ABI and allow transitional development from using errno to errno32, all the while
the annoying ILP64 vs LP64 vs LLP64 crap can be left entirely to the inline ABI. That would be the very 1st step in fixing ABI nonsense, shifting data
model crap out of the shared libraries. You can also use something like
typedef struct stdref
{
int32_t version;
char *name;
void *ud;
int32_t (*refcall)( void *ud, int32_t call, va_list va );
} stdref_t;
To internally manage different classes. If the name and version don't match what is supported then you use only what is known across all versions.
The class keyword should be treated like the inline keyword, only ever used on the static build part of the ABI while the shared part of the ABI
always uses the baseline C structs to keep things simple.