mfc >> A weird problem on union alignment, need help!

by xmllmx » Sun, 26 Aug 2007 03:05:17 GMT

To begin with code:

union XXX
{
double a;
char b;
double c;
};

XXX s;
size_t n1 = sizeof(XXX);
size_t n2 = __alignof(double);
size_t n3 = __alignof(XXX);

double* p1 = &s.a;
char* p2 = &s.b;
double* p3 = &s.c;
XXX* p4 = &s;

Compiler: VS 2005 + SP1

Output:
n1 = 8
n2 = 8 // the largest member in the union is 8-byte aligned!
n3 = 4 // ???, it should be 4 less than 8
p1 = 0x0012F5B4 // ???, it is not 8-byte aligned!
p2 = 0x0012F5B4 // ditto
p3 = 0x0012F5B4 // ditto
p4 = 0x0012F5B4 // ditto

Below is a related article copied from the site "The Old New Thing".
Because posting new comments to the original post has been disabled,
so I have to put it here. Please note the first comments to the post
by Roger Lipscombe, He/She says: "the C standard states that they must
be aligned suitably for the largest contained member." However, I
can't find any statement in the C standard, Is that implementation-
defined?

Thanks in advance!


================ Quotation ======================
The original link: http://blogs.msdn.com/oldnewthing/archive/2004/08/25/220195.aspx

Why can't you treat a FILETIME as an __int64?

The FILETIME structure represents a 64-bit value in two parts:

typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME;
You may be tempted to take the entire FILETIME structure and access it
directly as if it were an __int64. After all, its memory layout
exactly matches that of a 64-bit (little-endian) integer. Some people
have written sample code that does exactly this:

pi = (__int64*)&ft; // WRONG
(*pi) += (__int64)num*datepart; // WRONG
Why is this wrong?

Alignment.

Since a FILETIME is a structure containing two DWORDs, it requires
only 4-byte alignment, since that is sufficient to put each DWORD on a
valid DWORD boundary. There is no need for the first DWORD to reside
on an 8-byte boundary. And in fact, you've probably already used a
structure where it doesn't: The WIN32_FIND_DATA structure.

typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cFileName[ MAX_PATH ];
TCHAR cAlternateFileName[ 14 ];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;
Observe that the three FILETIME structures appear at offsets 4, 12,
and 20 from the beginning of the structure. They have been thrown off
8-byte alignment by the dwFileAttributes member.

Casting a FILETIME to an __int64 therefore can (and in the
WIN32_FIND_DATA case, will) create a misaligned pointer. Accessing a
misaligned pointer will raise a STATUS_DATATYPE_MISALIGNMENT exception
on architectures which require alignment.

Even if you are on a forgiving platform that performs automatic
alignment fixups, you can still run into trouble. More on this and
other consequences of alignment in the next few entries.

Exercise: Why are the LARGE_INTEGER and ULARGE_INTEGER structures not
affected?

===================================
Comments by Roger Lipscombe

LARGE_INTEGER and ULARGE_INTEGER are unions, and the C standard states
that they must be aligned suitably for the largest contained member --
which is a LONLONG or ULONGLONG, respectively.



mfc >> A weird problem on union alignment, need help!

by Bo Persson » Sun, 26 Aug 2007 06:09:06 GMT




:: To begin with code:
::
:: union XXX
:: {
:: double a;
:: char b;
:: double c;
:: };
::
:: XXX s;
:: size_t n1 = sizeof(XXX);
:: size_t n2 = __alignof(double);
:: size_t n3 = __alignof(XXX);
::
:: double* p1 = &s.a;
:: char* p2 = &s.b;
:: double* p3 = &s.c;
:: XXX* p4 = &s;
::
:: Compiler: VS 2005 + SP1
::
:: Output:
:: n1 = 8
:: n2 = 8 // the largest member in the union is 8-byte aligned!
:: n3 = 4 // ???, it should be 4 less than 8
:: p1 = 0x0012F5B4 // ???, it is not 8-byte aligned!
:: p2 = 0x0012F5B4 // ditto
:: p3 = 0x0012F5B4 // ditto
:: p4 = 0x0012F5B4 // ditto

Are you sure?

I get n1 == n2 == n3 == 8 and p1-p4 = 0x00494620

Seem pretty ok.


Bo Persson





mfc >> A weird problem on union alignment, need help!

by xmllmx » Sun, 26 Aug 2007 07:53:03 GMT





Maybe your computer is running on a 64-bit CPU. Mine is 32-bit



A weird problem on union alignment, need help!

by Geoff » Sun, 26 Aug 2007 08:23:04 GMT





Check your project properties, Compiler Code Generation and make sure
your Struct Member Alignment is default and not /Zp4 or you will get
this result.


A weird problem on union alignment, need help!

by Bo Persson » Sun, 26 Aug 2007 18:05:58 GMT





:::
::::: To begin with code:
:::::
::::: union XXX
::::: {
::::: double a;
::::: char b;
::::: double c;
::::: };
:::::
::::: XXX s;
::::: size_t n1 = sizeof(XXX);
::::: size_t n2 = __alignof(double);
::::: size_t n3 = __alignof(XXX);
:::::
::::: double* p1 = &s.a;
::::: char* p2 = &s.b;
::::: double* p3 = &s.c;
::::: XXX* p4 = &s;
:::::
::::: Compiler: VS 2005 + SP1
:::::
::::: Output:
::::: n1 = 8
::::: n2 = 8 // the largest member in the union is 8-byte aligned!
::::: n3 = 4 // ???, it should be 4 less than 8
::::: p1 = 0x0012F5B4 // ???, it is not 8-byte aligned!
::::: p2 = 0x0012F5B4 // ditto
::::: p3 = 0x0012F5B4 // ditto
::::: p4 = 0x0012F5B4 // ditto
:::
::: Are you sure?
:::
::: I get n1 == n2 == n3 == 8 and p1-p4 = 0x00494620
:::
::: Seem pretty ok.
:::
::: Bo Persson
::
:: Maybe your computer is running on a 64-bit CPU. Mine is 32-bit

No, it has plain Win XP-SP2 and Visual C++ Express.

You must have some odd project setting or pragma somewhere.


Bo Persson




A weird problem on union alignment, need help!

by Norman Diamond » Mon, 27 Aug 2007 08:38:25 GMT

agree with other posters that there are probably some unwanted project
settings or #pragma directives, causing this unwanted result.

To answer this question:

If a project setting or a #pragma tells the compiler not to conform to the
standard then the compiler should not conform to the standard.

If you have the settings that you want, then the relevant clause in the C
standard (1999 edition) is 6.7.2.1. Page 103 paragraphs 12, 13, and 15 make
it clear that the structure has to be aligned in a way that, with padding
allowed in places other than the beginning of the structure, each member of
the structure will be aligned for its own needs.

As far as I can tell, strange results are still possible. Consider an
implementation where int is 4 bytes long and requires alignment at a
multiple of 4, and long is 8 bytes long and requires alignment at a multiple
of 8.
struct S {
int I;
long L;
int J;
} A[61];
As far as I can tell, it would be OK for the compiler to locate A[0] at
address 0x10000004, and the entire array of structures can avoid padding.

__alignof(S) would invoke WinGod's law and terminate the discussion.


"xmllmx" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...



Similar Threads

1. A weird problem on structure and union alignment

2. Bitfields and chars alignment for unions

3. Byte alignment in union

Suppose i do something like this:

template <typename T>
class Foo
{

union 
{
	T c[4];
	struct
	{
		T c0, c1, c2, c3;
	}
};

};

with T a built-in type eg. float

does the standard guarantee that c[i] and ci (i in 0...3) occuppy the
same bytes in memory ?

best regards,
Ares Lagae

4. Help (No really I need Help with Help :) - CSharp/C#

5. Stack alignment vs. struct alignment

I'm compiling for Win32 and am using the default struct alignment, which I 
believe is 8 bytes.  I have the following structure:

struct TData
   {
   double value;
   bool isNull;
   };

I'm expecting that to be aligned to 8 bytes, and sure enough the 
__alignof() operator returns 8 for this structure.  However, when this 
object gets created on the stack, it's not 8-byte aligned (the address has 
a remainder of 4).  How do I force objects on the stack to obey the 
compiler alignment setting?  The alignment is a critical part of some 
legacy code that I'm trying to migrate and I can't use byte alignment.  
Any help would be appreciated.

-- 

6. Explanation needed for weird method.

7. adding alignment support n2140 & n2165 inconsistent alignment value calculation

8. RAD2007 / CBuilder - Mixing code with one byte alignment and quad word alignment