Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

portable method of getting alignment of an arbitrary type...

6 views
Skip to first unread message

Chris M. Thomasson

unread,
Mar 2, 2009, 10:32:47 AM3/2/09
to
Does anybody have any ideas on how I can improve the following hack:
_______________________________________________________________________
#include <stdio.h>
#include <stddef.h>


#define ALIGN_OF_X(mp_type, mp_var, mp_line) { \
struct ALIGN_OF ## mp_line { \
char pad; \
mp_type type; \
}; \
(*(mp_var)) = offsetof(struct ALIGN_OF ## mp_line, type); \
} ((void)0)


#define ALIGN_OF(mp_type, mp_var) \
ALIGN_OF_X(mp_type, mp_var, __LINE__)


int main(void) {
size_t alignment;

struct foo {
char a[2];
double b[5];
long int c[6];
char d;
};

ALIGN_OF(char, &alignment);
printf("ALIGN_OF(char) == %lu\n", (unsigned long)alignment);

ALIGN_OF(short int, &alignment);
printf("ALIGN_OF(short int) == %lu\n", (unsigned long)alignment);

ALIGN_OF(int, &alignment);
printf("ALIGN_OF(int) == %lu\n", (unsigned long)alignment);

ALIGN_OF(long int, &alignment);
printf("ALIGN_OF(long int) == %lu\n", (unsigned long)alignment);

ALIGN_OF(float, &alignment);
printf("ALIGN_OF(float) == %lu\n", (unsigned long)alignment);

ALIGN_OF(double, &alignment);
printf("ALIGN_OF(double) == %lu\n", (unsigned long)alignment);

ALIGN_OF(struct foo, &alignment);
printf("ALIGN_OF(struct foo) == %lu\n", (unsigned long)alignment);

return 0;
}
_______________________________________________________________________


?


Thanks.

Mark Wooding

unread,
Mar 2, 2009, 11:19:56 AM3/2/09
to
"Chris M. Thomasson" <n...@spam.invalid> writes:

> Does anybody have any ideas on how I can improve the following hack:

> #define ALIGN_OF_X(mp_type, mp_var, mp_line) { \


> struct ALIGN_OF ## mp_line { \
> char pad; \
> mp_type type; \
> }; \
> (*(mp_var)) = offsetof(struct ALIGN_OF ## mp_line, type); \
> } ((void)0)
>
>
> #define ALIGN_OF(mp_type, mp_var) \
> ALIGN_OF_X(mp_type, mp_var, __LINE__)

That seems very inconvenient.

#define alignof(type) offsetof(struct { char a__; type b__; }, b__)

That is, an untagged struct meets the requirements of 7.17p3 so you can
use offsetof directly rather than having to assign to a pointless
temporary. Also, I think a lowercase name fits in better with offsetof.

-- [mdw]

Eric Sosman

unread,
Mar 2, 2009, 11:31:30 AM3/2/09
to
Chris M. Thomasson wrote:
> Does anybody have any ideas on how I can improve the following hack:
> _______________________________________________________________________
> #include <stdio.h>
> #include <stddef.h>
>
>
> #define ALIGN_OF_X(mp_type, mp_var, mp_line) { \
> struct ALIGN_OF ## mp_line { \
> char pad; \
> mp_type type; \
> }; \
> (*(mp_var)) = offsetof(struct ALIGN_OF ## mp_line, type); \
> } ((void)0)

You can streamline it a little by eliminating the
struct tag and associated baggage, and just passing the
result back as a value instead of using the pointer:

#define ALIGNOF(type) offsetof(struct{char p; type t;},t)
size_t align_of_double = ALIGNOF(double);
size_t align_of_long_long = ALIGNOF(long long);
...

Adding a little more obfuscation to the identifiers `p' and `t'
might be helpful -- I know of no sure-fire way to do so, but
prepending an underscore is a common (albeit risky) dodge.

It is conceivable, though unlikely, that a compiler might
insert *more* padding than is strictly necessary, causing the
macro to overstate the alignment requirement. A more common
failing is that the compiler may enforce an alignment that is
adequate but sub-optimal: On one popular architecture, for
instance, it is faster to access a double aligned to an 8-byte
boundary than one that is merely 4-byte aligned, but both
alignments "work" and ALIGNOF(double) gives 4: adequate but
not best.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Chris M. Thomasson

unread,
Mar 2, 2009, 12:26:50 PM3/2/09
to
Thank you Eric and Mark! I really appreciate that. I was getting a warning
wrt the unnamed struct definition on one of my compilers (MSVC 6) as
follows:


unnamed type definition in parentheses


So, I decided to try something like this; which seems to work:


__________________________________________________________________
#include <stdio.h>
#include <stddef.h>


#define ALIGN_OF_XX(mp_type, mp_line) offsetof( \
struct ALIGN_OF_XX ## mp_line { \
char pad__ ## mp_line; \
mp_type type__ ## mp_line; \
}, type__ ## mp_line \
)

#define ALIGN_OF_X(mp_type, mp_line) \
ALIGN_OF_XX(mp_type, mp_line)

#define ALIGN_OF(mp_type) \
ALIGN_OF_X(mp_type, __LINE__)


int main(void) {


struct foo {
char a[2];
double b[5];
long int c[6];
char d;
};

printf(
"ALIGN_OF(char) == %lu\n"


"ALIGN_OF(short int) == %lu\n"

"ALIGN_OF(int) == %lu\n"


"ALIGN_OF(long int) == %lu\n"

"ALIGN_OF(float) == %lu\n"
"ALIGN_OF(long double) == %lu\n"
"ALIGN_OF(double) == %lu\n"


"ALIGN_OF(struct foo) == %lu\n",

(unsigned long)ALIGN_OF(char),
(unsigned long)ALIGN_OF(short int),
(unsigned long)ALIGN_OF(int),
(unsigned long)ALIGN_OF(long int),
(unsigned long)ALIGN_OF(float),
(unsigned long)ALIGN_OF(long double),
(unsigned long)ALIGN_OF(double),
(unsigned long)ALIGN_OF(struct foo)
);

return 0;
}
__________________________________________________________________


It compiles without warning now on (MSVC, Comeau, GCC); I still need to test
it on Sun CC, and Intel, ect... I did not know that you could legally define
a struct like that. Well, it CERTAINLY improves the original crap I had!!

Thanks again.

Chris M. Thomasson

unread,
Mar 2, 2009, 12:29:12 PM3/2/09
to
"Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
news:goh1l8$rab$1...@news.motzarella.org...

> Chris M. Thomasson wrote:
>> Does anybody have any ideas on how I can improve the following hack:
>> _______________________________________________________________________
>>[...]

>
> It is conceivable, though unlikely, that a compiler might
> insert *more* padding than is strictly necessary, causing the
> macro to overstate the alignment requirement. A more common
> failing is that the compiler may enforce an alignment that is
> adequate but sub-optimal: On one popular architecture, for
> instance, it is faster to access a double aligned to an 8-byte
> boundary than one that is merely 4-byte aligned, but both
> alignments "work" and ALIGNOF(double) gives 4: adequate but
> not best.

Humm... Good point; I had not really considered this possibility. Well, can
you think of a scenario in which the `ALIGN_OF' macro would return a value
that is not compatible with the given type?


Thanks for all your help Eric.

Chris M. Thomasson

unread,
Mar 2, 2009, 12:35:49 PM3/2/09
to
"Chris M. Thomasson" <n...@spam.invalid> wrote in message
news:lGUql.53103$rb1....@newsfe02.iad...

> "Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
> news:goh1l8$rab$1...@news.motzarella.org...
>> Chris M. Thomasson wrote:
>>> Does anybody have any ideas on how I can improve the following hack:
>>> _______________________________________________________________________
>>>[...]
>>
>> It is conceivable, though unlikely, that a compiler might
>> insert *more* padding than is strictly necessary, causing the
>> macro to overstate the alignment requirement. A more common
>> failing is that the compiler may enforce an alignment that is
>> adequate but sub-optimal: On one popular architecture, for
>> instance, it is faster to access a double aligned to an 8-byte
>> boundary than one that is merely 4-byte aligned, but both
>> alignments "work" and ALIGNOF(double) gives 4: adequate but
>> not best.
>
> Humm... Good point; I had not really considered this possibility. [...]

FWIW, I notice that MSVC and MingW give different alignment requirements for
type `long double' on the same exact platform;I get the following output:


MSVC output (32-bit x86):

sizeof(long double) == 8
ALIGN_OF(long double) == 8


GCC output (32-bit x86) <windows>:

sizeof(long double) == 12
ALIGN_OF(long double) == 4


from the following program:


#include <stdio.h>
#include <stddef.h>


#define ALIGN_OF_XX(mp_type, mp_line) offsetof( \
struct ALIGN_OF_XX ## mp_line { \
char pad__ ## mp_line; \
mp_type type__ ## mp_line; \
}, type__ ## mp_line \
)

#define ALIGN_OF_X(mp_type, mp_line) \
ALIGN_OF_XX(mp_type, mp_line)

#define ALIGN_OF(mp_type) \
ALIGN_OF_X(mp_type, __LINE__)


int main(void) {
printf(
"sizeof(long double) == %lu\n"
"ALIGN_OF(long double) == %lu\n",
(unsigned long)sizeof(long double),
(unsigned long)ALIGN_OF(long double)
);

return 0;
}


Chris M. Thomasson

unread,
Mar 2, 2009, 1:17:45 PM3/2/09
to
"Chris M. Thomasson" <n...@spam.invalid> wrote in message
news:7EUql.53102$rb1....@newsfe02.iad...

> Thank you Eric and Mark! I really appreciate that. I was getting a warning
> wrt the unnamed struct definition on one of my compilers (MSVC 6) as
> follows:
>
>
> unnamed type definition in parentheses
>
>
> So, I decided to try something like this; which seems to work:
> __________________________________________________________________
> #include <stdio.h>
> #include <stddef.h>
>
>
> #define ALIGN_OF_XX(mp_type, mp_line) offsetof( \
> struct ALIGN_OF_XX ## mp_line { \
> char pad__ ## mp_line; \
> mp_type type__ ## mp_line; \
> }, type__ ## mp_line \
> )
>
> #define ALIGN_OF_X(mp_type, mp_line) \
> ALIGN_OF_XX(mp_type, mp_line)
>
> #define ALIGN_OF(mp_type) \
> ALIGN_OF_X(mp_type, __LINE__)

> [...]

This has problems. I cannot use the macro more than once on the same line.
Oh well, I will use unnamed struct and disable the warning in MSVC. Oh well.

George Peter Staplin

unread,
Mar 2, 2009, 1:33:04 PM3/2/09
to
Chris M. Thomasson wrote:


This most likely has something to do with MSVC not supporting the C99
standard "long double" as well as GCC. I would imagine MSVC's C runtime is
missing powl() too.

In x86_64 mode for the same processor you might find that the "long double"
alignment is a multiple of 16. IIRC gcc uses the SSE instructions for
floating point for that architecture, rather than the i387 instructions,
and depending on which instructions are used, that may or may not require
128-bit alignment for the cache line access.

-George

Ben Bacarisse

unread,
Mar 2, 2009, 1:59:50 PM3/2/09
to
George Peter Staplin <geor...@xmission.com> writes:

> Chris M. Thomasson wrote:
,snip>


>> MSVC output (32-bit x86):
>>
>> sizeof(long double) == 8
>> ALIGN_OF(long double) == 8
>>
>> GCC output (32-bit x86) <windows>:
>>
>> sizeof(long double) == 12
>> ALIGN_OF(long double) == 4
>
> This most likely has something to do with MSVC not supporting the C99
> standard "long double" as well as GCC.

Nit-pick: long double is in C90. A lot of library support for long
double was added in C99 which is, I image, what you mean.

--
Ben.

Eric Sosman

unread,
Mar 2, 2009, 2:07:00 PM3/2/09
to

The offsetof-in-a-suitable-struct trick will always yield
a value that is "compatible" in the sense that "it works:" the
program will run correctly. That is, there is no undefined
behavior in

char *p = malloc(ALIGNOF(T) + sizeof(T)); // assume success
*( (T*)(p + ALIGNOF(T)) ) = some_T_value;

The ALIGNOF value may not be the "best" value, but will always
be "sufficient."

--
Eric Sosman
eso...@ieee-dot-org.invalid

Keith Thompson

unread,
Mar 2, 2009, 2:31:20 PM3/2/09
to

No, I don't think he's talking about library support, since the
program doesn't use any relevant library routines.

There's a common misconception that long double is a C99-specific
feature. It isn't, and the requirements for long double did not
change significantly between C90 and C99.

The real issue here seems to be that MSVC uses the same 64-bit
representation for long double that it uses for double, whereas gcc
uses a 96-bit representation (most likely 80 bits plus 16 bits of
padding). Both implementations are conforming, at least with regard
to this feature; both C90 and C99 allow double and long double to have
the same representation.

(There's a particular implementation that uses the gcc compiler and
Microsoft's runtime library (dgjpp, I think) that has a problem in
this area, because the compiler and the library assume different
representations for long double.)

--
Keith Thompson (The_Other_Keith) k...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Chris M. Thomasson

unread,
Mar 9, 2009, 8:04:53 AM3/9/09
to

"Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
news:gohaoq$9o8$1...@news.motzarella.org...

Thanks for you time Sir.

0 new messages