A weird problem on structure and union alignment

X

xmllmx

Please forgive me for cross-posting. I've post this to
microsoft.publoc.vc.mfc. But I can't get any response. Maybe only MFC-
related topics are cared there.

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.
 
R

red floyd

xmllmx said:
Please forgive me for cross-posting. I've post this to
microsoft.publoc.vc.mfc. But I can't get any response. Maybe only MFC-
related topics are cared there.

However, it's off-topic here, as the Standard makes no promises as to
alignment.
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;

There are other microsoft.public groups, as well as
comp.windows.ms.programmer. Follow-up set to that group.
 
G

Gianni Mariani

xmllmx said:
Please forgive me for cross-posting. I've post this to
microsoft.publoc.vc.mfc. But I can't get any response. Maybe only MFC-
related topics are cared there.

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


I posted the code below on an earlier article on alignment. I added
some of your code to it and printed some stuff. I don't think I have
SP1 installed - however with VS 2005 I get consistent numbers, namely
alignment of XXX is 8.


template <typename T>
struct noreference
{
typedef T type;
};

template <typename T>
struct noreference<T&>
{
typedef T type;
};



template <typename T>
struct alignof_static
{
struct Helper1 { T v; };
struct Helper2 { char c; Helper1 v; };

static const unsigned value = sizeof(Helper2)-sizeof(Helper1);
};

template <typename T>
struct alignof_noref_static
{
static const unsigned value = alignof_static<typename
noreference<T>::type >::value;
};

template <typename T>
unsigned alignof()
{
return alignof_static<T>::value;
}

template <typename T>
unsigned alignof_noref()
{
return alignof_noref_static<T>::value;
}

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

#include <iostream>
int main()
{
std::cout << alignof<XXX>() << "\n";
std::cout << alignof<double>() << "\n";
std::cout << __alignof(XXX) << "\n";
std::cout << __alignof(double) << "\n";
}
 
X

xmllmx

I posted the code below on an earlier article on alignment. I added
some of your code to it and printed some stuff. I don't think I have
SP1 installed - however with VS 2005 I get consistent numbers, namely
alignment of XXX is 8.

template <typename T>
struct noreference
{
typedef T type;

};

template <typename T>
struct noreference<T&>
{
typedef T type;

};

template <typename T>
struct alignof_static
{
struct Helper1 { T v; };
struct Helper2 { char c; Helper1 v; };

static const unsigned value = sizeof(Helper2)-sizeof(Helper1);

};

template <typename T>
struct alignof_noref_static
{
static const unsigned value = alignof_static<typename
noreference<T>::type >::value;

};

template <typename T>
unsigned alignof()
{
return alignof_static<T>::value;

}

template <typename T>
unsigned alignof_noref()
{
return alignof_noref_static<T>::value;

}

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

};

#include <iostream>
int main()
{
std::cout << alignof<XXX>() << "\n";
std::cout << alignof<double>() << "\n";
std::cout << __alignof(XXX) << "\n";
std::cout << __alignof(double) << "\n";



}- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

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

Juha Nieminen

xmllmx said:
p1 = 0x0012F5B4 // ???, it is not 8-byte aligned!

Why do you expect it to be? I believe that in a 32-bit architecture a
64-bit double doesn't necessarily need to be aligned at the 64-bit
boundary, but it's ok for it to be at the 32-bit boundary without
suffering any penalty.
 

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

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top