Portable alignof

W

William Ahern

Thoughts, comments?

#ifdef HAVE_TYPEOF

/*
* Can use arbitrary expressions
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; typeof(t) x; }, x) : 1)

#else

/*
* Can only use types
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; t x; }, x) : 1)

#endif
 
B

Ben Pfaff

William Ahern said:
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; t x; }, x) : 1)

I'm not certain whether that's portably correct or not, but I
must say that, regardless, it's remarkably clever.
 
K

Keith Thompson

William Ahern said:
Thoughts, comments?

#ifdef HAVE_TYPEOF

/*
* Can use arbitrary expressions
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; typeof(t) x; }, x) : 1)

#else

/*
* Can only use types
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; t x; }, x) : 1)

#endif

I don't see a problem with it, but I don't think the test for
sizeof(t) is necessary:

#define alignof(t) \
offsetof(struct { char c; t x; }, x)
 
P

Peter Nilsson

William said:
Thoughts, comments?
...
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; t x; }, x) : 1)

Looks okay, but realise that whilst it will return a suitable
alignment,
it may not return the minimum alignment. For instance, a 4 byte
int may only require two byte alignment on a given machine, but
because of compiler dependant padding settings, alignof might
return 4 (or even 8 etc...).

Your test if sizeof(t) > 1 would indicate that you have already
encountered such an issue with char in that regard.

If you're paranoid and you want a little more precision, you might
want to take the minimum of your expression and sizeof(t)...

#define min(a,b) ((a) < (b) ? (a) : (b))

#define simple_alignof(t) \
(sizeof (t) > 1 ? offsetof(struct { char c; t x; }, x) : 1)

#define alignof(t) min(sizeof(t), simple_alignof(t))
 
C

CBFalconer

Ben said:
I'm not certain whether that's portably correct or not, but I
must say that, regardless, it's remarkably clever.

And it should be efficient, generating a simple constant. This
should have appeared in the making fatal assumptions thread, where
just that sort of problem led to various assumptions.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
P

pemo

William said:
Thoughts, comments?

#ifdef HAVE_TYPEOF

/*
* Can use arbitrary expressions
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; typeof(t) x; },
x) : 1)

#else

/*
* Can only use types
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; t x; }, x) : 1)

#endif

Could someone provide an example of how to use this please - and the typeof
macro if poss?
 
J

Jordan Abel

Could someone provide an example of how to use this please - and the typeof
macro if poss?

typeof isn't a macro, it's a non-standard keyword. That's why it's
guarded by a HAVE_TYPEOF macro.
 
R

REH

Keith said:
I don't see a problem with it, but I don't think the test for
sizeof(t) is necessary:

#define alignof(t) \
offsetof(struct { char c; t x; }, x)

--

Isn''t the test needed because, with the above, alignof(char) will
yield 2?

REH
 
R

REH

William said:
Thoughts, comments?

#ifdef HAVE_TYPEOF

/*
* Can use arbitrary expressions
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; typeof(t) x; }, x) : 1)

#else

/*
* Can only use types
*/
#define alignof(t) \
((sizeof (t) > 1)? offsetof(struct { char c; t x; }, x) : 1)

#endif

I think it's very clever. I am wondering, though, what is the
necessity of typeof? I assume that if it is available, you want to use
it. That would imply it somehow makes its form of alignof "better" but
I cannot tell why. please explain.

REH
 
K

Keith Thompson

REH said:
Isn''t the test needed because, with the above, alignof(char) will
yield 2?

Nope. Given struct { char c; char x; }, c has offset 0 and x has
offset 1 (unless the compiler decides to insert padding between c and
x).
 
R

REH

Keith said:
Nope. Given struct { char c; char x; }, c has offset 0 and x has
offset 1 (unless the compiler decides to insert padding between c and
x).

Ah, you're right!

REH
 
K

Keith Thompson

REH said:
I think it's very clever. I am wondering, though, what is the
necessity of typeof? I assume that if it is available, you want to use
it. That would imply it somehow makes its form of alignof "better" but
I cannot tell why. please explain.

That's explained (briefly) in the comments. Assuming the non-standard
typeof, like the standard sizeof, can take either a type name or an
expression as an argument. For a type, it yields the type; for an
expression, it yields the type of the expression. (I'm only guessing
here, but it seems like a reasonable semantics.)

Then if an implementation provides typeof, the alignof() macro can be
applied either to a type or an expression. If there is no typeof,
alignof can only be applied to a type.

Note also that the type argument t must be such that "t x;" declares
an object (actually a member) of type t. alignof(int[10]) would cause
a syntax error, since "t x;" would expand to "int[10] x;" rather than
the correct "int x[10];". This can be worked around by creating a
typedef such as "typedef int int10[10];" and using alignof(int10).
 
R

REH

Keith said:
That's explained (briefly) in the comments. Assuming the non-standard
typeof, like the standard sizeof, can take either a type name or an
expression as an argument. For a type, it yields the type; for an
expression, it yields the type of the expression. (I'm only guessing
here, but it seems like a reasonable semantics.)

Then if an implementation provides typeof, the alignof() macro can be
applied either to a type or an expression. If there is no typeof,
alignof can only be applied to a type.

Note also that the type argument t must be such that "t x;" declares
an object (actually a member) of type t. alignof(int[10]) would cause
a syntax error, since "t x;" would expand to "int[10] x;" rather than
the correct "int x[10];". This can be worked around by creating a
typedef such as "typedef int int10[10];" and using alignof(int10).

--

Thanks Keith. I must have read the code a dozen times trying to
detemine why it was "better." I missed that comment every time.

REH
 
W

William Ahern

I don't see a problem with it, but I don't think the test for
sizeof(t) is necessary:

#define alignof(t) \
offsetof(struct { char c; t x; }, x)

To get a valid alignment I think your right, and really that's
all this is good for. It doesn't guarantee the smallest valid
alignment, though certainly less wasteful than sizeof when used on
structures.

I think I was contemplating scenarios where sizeof (char) ==
sizeof (short), but in retrospect it shouldn't matter.

Also, Google shows that the exact code above has been posted at least
twice before, most recently in 2004. Maybe I was recalling a latent
memory ;)
 
E

Eric Sosman

William Ahern wrote On 03/09/06 15:38,:
To get a valid alignment I think your right, and really that's
all this is good for. It doesn't guarantee the smallest valid
alignment, though certainly less wasteful than sizeof when used on
structures.

If that's a concern, one could "improve" the macro to

#define alignof(t) \
(offsetof( struct { char c; t x; }, x ) <= sizeof(x) \
? offsetof( struct { char c; t x; }, x ) \
: sizeof(x))

This is still not guaranteed to be minimal, but might be of
use if the compiler likes to do things like

struct {
char c; /* 1 byte at offset 0 (required) */
/* 5 padding bytes (over-generous) */
short x; /* 2 bytes at offset 6 */
}

Let's see: We know that the alignment requirement for a
type is a divisor of its sizeof, and we also know that it's
a divisor of the offsetof as used in the macros above. A
further "improvement" might be to use the greatest common
divisor of these two as an estimate of the requirement, but
computing GCD's without a loop and without temporary variables
would be horrible. It'd pretty much need to be a run-time
computation, not a compile-time constant -- and it STILL
wouldn't necessarily be minimal!
 
P

pemo

Jordan said:
typeof isn't a macro, it's a non-standard keyword. That's why it's
guarded by a HAVE_TYPEOF macro.

Ok, thatnks Jordan.

So, with this removed [whose keyword is it?], is there an example of what
this is for/does please?
 
W

William Ahern

Jordan said:
typeof isn't a macro, it's a non-standard keyword. That's why it's
guarded by a HAVE_TYPEOF macro.

Ok, thatnks Jordan.

So, with this removed [whose keyword is it?],

AFAIK, typeof is a very common extension (GCC, TinyCC, TenDRA,
MSVC-maybe, Sun, IBM, HP). Basically, it's a magical operator that can be
used in-place of type declarations. So, you can do things like:

int i;
typeof(i) d; /* d has the same type as i */
is there an example of what this is for/does please?

I'm writing a memory allocator library (and interface), so recently I've
just been interested in object alignment restrictions. The point is
frequently drive home here that it's impossible to portably
determine the strictest alignment required (i.e. the boundary
that malloc(3) will align pointer values on to guarantee it can point to
any object). But, fortunately in some particular cases my needs were
a little less. I just wanted to be able to determine a safe alignment for
some specific internal structures; the ones that hold the state of the
arena and object pool allocators. The state structures themselves came
from the same blob of allocated memory.

http://25thandClement.com/~william/projects/libarena.html
 
K

Keith Thompson

William Ahern said:
To get a valid alignment I think your right, and really that's
all this is good for. It doesn't guarantee the smallest valid
alignment, though certainly less wasteful than sizeof when used on
structures.

I think I was contemplating scenarios where sizeof (char) ==
sizeof (short), but in retrospect it shouldn't matter.

Which, of course, implies that sizeof(short)==1, and CHAR_BIT>=16.
Also, Google shows that the exact code above has been posted at least
twice before, most recently in 2004. Maybe I was recalling a latent
memory ;)

I've used (but not posted) something very similar myself, in a program
that shows the characteristics of a system's data types:

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t)))

My logs indicate that I wrote it in 2001.
 
K

Keith Thompson

Eric Sosman said:
William Ahern wrote On 03/09/06 15:38,:

If that's a concern, one could "improve" the macro to

#define alignof(t) \
(offsetof( struct { char c; t x; }, x ) <= sizeof(x) \
? offsetof( struct { char c; t x; }, x ) \
: sizeof(x))

This is still not guaranteed to be minimal, but might be of
use if the compiler likes to do things like

struct {
char c; /* 1 byte at offset 0 (required) */
/* 5 padding bytes (over-generous) */
short x; /* 2 bytes at offset 6 */
}
[...]

A more likely scenario is a system where a short (which is, say, 2
bytes) *can* be accessed if it's at an odd address, but can be
accessed more efficiently if it's at an even address. On such a
system, the compiler is likely to leave a 1-byte gap between the char
and the short in your declaration above, even though it doesn't
strictly need to (and might not if you use a system-specific "pack"
pragma, for example).

The simple form of the alignof():

#define alignof(t) \
offsetof(struct { char c; t x; }, x)

tells you how the compiler *chooses* to align a given data type --
which, in most scenarios I can think of, is exactly what you want. If
I'm manually allocating data elements within a malloc()ed buffer, for
example, alignof() will tell me the best place to put them. If I want
to save space, I might use a system-specific alignof() macro that uses
a pack pragma or some similar mechanism. (If I *really* want to save
space, I won't leave any gaps at all, and I'll use memcpy() to extact
the data elements.)
 
W

William Ahern

Jordan said:
Could someone provide an example of how to use this please - and the
typeof macro if poss?

typeof isn't a macro, it's a non-standard keyword. That's why it's
guarded by a HAVE_TYPEOF macro.

Ok, thatnks Jordan.

So, with this removed [whose keyword is it?],

AFAIK, typeof is a very common extension (GCC, TinyCC, TenDRA,
MSVC-maybe, Sun, IBM, HP). Basically, it's a magical operator that can be
used in-place of type declarations. So, you can do things like:

int i;
typeof(i) d; /* d has the same type as i */

And, I dare say, given the reception in this forum of typeof, if I were
a betting man I'd expect to see it in a future C standard. When typeof
is mentioned you'll typically get some gentle nudging about it's
non-existence in the C specification. However, for most other
non-C constructs you'll usually hear fire and brimstone speeches,
hopefully followed by convincing reasons why such a construct is a poor
idea, even on its own merits.

Also, the fact that typeof has found its way into so many compilers also
bodes well for inclusion. But, I suppose this discussion belongs in
comp.std.c ;)

I mention this because alignof is also found in some compilers as an
operator, which is why I was interested in writing a macro. Unlike typeof,
however, it's not nearly as widespread, AFAIK.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,948
Members
47,500
Latest member
ArianneJsb

Latest Threads

Top