Shao Miller
6/29/2011 7:37:00 PM
On 6/29/2011 12:23, Lauri Alanko wrote:
> In article<iufcld$fgi$1@dont-email.me>,
> Shao Miller<sha0.miller@gmail.com> wrote:
>> In C1X, we have the 'alignof' operator and some other alignment friends.
>>
>> Mr. C. M. Thomasson has offered an 'ALIGNOF' macro that goes something like:
>>
>> #define ALIGNOF(type) (offsetof(struct { char c; type m; }, m))
>>
>> Which seems very nice to me, except for a couple of minor weaknesses.
>>
>> Both the C1X operator as well as this macro require that the type is a
>> completed object type.
>
> I'm aware of these, but these are only useful for runtime checks, and
> here I was interested in static properties of types.
>
I'm not sure I grok "only useful for runtime checks." Both result in
integer constant expressions and so are suitable for such things as
enumeration values or array sizes; possible translation-time determinations.
> (Also, the usefulness of a standard alignof seems limited unless we
> also have a standard way of manipulating addresses to ensure their
> alignment, and to my understanding the new standard doesn't provide
> this, only aligned_alloc. The common approach of manipulating the
> lower bits of a pointer-turned-int is still implementation-defined.)
>
C1X has the '_Alignas' keyword as an "alignment specifier." I don't
know of a C89/C99 counterpart.
With '*alloc'-allocated storage, you can perform your own computations
to ensure any objects stored therein adhere to whatever alignment
requirements you want. My 'pfxalloc' example in another thread provides
an example (though it could certainly use improvement).
>> Do you have a specific goal that you are trying to accomplish, or are
>> you just curious? Perhaps there are other Standard guarantees which
>> might apply to some situation you might be thinking about.
>
> I was considering one approach to the age-old "opaque typedef"
> problem.
By co-incidence, I was pondering this one last night. :)
> Say I have a type for dictionaries:
>
> typedef struct Dict Dict;
> Dict* dict_new(....);
> void* dict_get(Dict* dict, void* key);
>
> Now I want to have a separate type IntDict for dicts whose keys are
> ints. I can use the implementation for Dict, I just want a distinct
> type to ensure that other Dicts can't be passed to IntDict functions.
If I understand your requirements correctly, you wish to have another
"pointerish" type that can point at a 'Dict' but is nonetheless distinct
from 'Dict *'; not compatible.
> One approach is this:
>
> typedef struct IntDict IntDict;
>
> inline IntDict* intdict_new(....) {
> return (IntDict*) dict_new(....);
> }
>
> inline void* intdict_get(IntDict* idict, int key) {
> return dict_get((Dict*) idict,&key);
> }
>
> This seemed appealing to me, because we get a distinct type, and
> IntDict* is directly a pointer type which is convenient for its
> void*-compatibility.
>
Hmmm... If someone has a 'Dict *' value converted to a 'void *' value,
what'll stop them from passing that to 'intdict_get', regardless of the
distinct 'IntDict *' type?
> But if the above doesn't work, I'm forced to resort to struct-wrapping
> the actual pointer:
>
Not necessarily.
> typedef struct IntDictP {
> Dict* dict_;
> } IntDictP;
>
> inline IntDictP intdict_new(....) {
> return (IntDictP) { dict_new(....) };
> }
>
> inline void* intdict_get(IntDictP idict, int key) {
> return dict_get(idict.dict_,&key);
> }
>
> I think this is uglier, since now the user of the intdict API has to
> use a special handle type instead of an ordinary pointer. But perhaps
> this is then the only portable way to do this.
Are they going to be passing a 'void *' or an 'xxx' for the most part?
Are you trying to prevent API users from ever including any of the
definition of 'Dict'? If not, what about using array types with
something like:
/**** dictp.h */
#ifdef DICTP_H_OK_
struct s_dict_ {
double d;
};
typedef struct s_dict_ a_int_dict_[1][1][1];
#undef DICTP_H_OK_
#endif /* DICTP_H_OK_ */
/**** dict.h */
#ifndef DICT_H_
/***
* Private details
* API users shouldn't include this header directly
*/
#define DICTP_H_OK_
#include "dictp.h"
/*** Object types */
typedef struct s_dict_ Dict;
typedef a_int_dict_ IntDict;
/*** Function declarations */
extern Dict * NewDict(void);
extern void * GetDict(Dict *, void *);
extern IntDict * NewIntDict(void);
extern void * GetIntDict(IntDict *, int);
#endif /* DICT_H_ */
/**** dict.c */
#include <stdlib.h>
#include "dict.h"
Dict * NewDict(void) {
return malloc(sizeof (Dict));
}
void * GetDict(Dict * dict, void * key) {
/* Whatever */
return 0;
}
IntDict * NewIntDict(void) {
return (IntDict *) NewDict();
}
void * GetIntDict(IntDict * idict, int key) {
/* Whatever */
return 0;
}
/**** Test program */
#include <stdlib.h>
#include "dict.h"
int main(void) {
Dict * foo = NewDict();
IntDict * bar = NewIntDict();
free(foo);
free(bar);
return 0;
}