struct and union alignment

S

S.Tobias

pete said:
S.Tobias wrote:

Afterthought: the implementation actually need not try to hide it.
It might even allow accessing objects with sub-byte resolution.
But this is implementation defined, and undefined by the standard.

Since void* does not point to any object, is a "free pointer",
the Standard must specify that the void* values which are valid
for char*, are also valid for void*, otherwise undefined. And
this is what a programmer must be concerned about.
I'm still not understanding what you're saying.

The implementation defines byte (char) not what the machine thinks
is a byte (I used name "octet" for machine-bytes). Everything
else is built of bytes.
(I hope my use of the word "octet" is not improper, it wasn't reserved
by the Standard.)
If a char has the same representation as char*,

No, I didn't say that, it's nonsense. All I said is that the
implementation uses machine representation of pointer for char* (and
possibly for other pointer types). Of course, this machine representation
must be composed of multiple of 4-octets (or padded up to that boundary),
so that a pointer type object may be accessed as char array.
and sizeof(char*) is 4, then,

It might be any value. If it's 4, then char* object takes 4 bytes
(or 16 octets, in machine speak).
is each byte of the four bytes of your char*,
also composed of 4 octets?

Of course. On C level everything is built of bytes.
Do you think a pointer to char should have any trouble
stepping through all the bytes of an object of type pointer to char?
/* BEGIN new.c */
#include <stdio.h>
int main(void)
{
char *object, *pointer;
size_t n;
n = sizeof object;
object = NULL;
pointer = (char *)&object;
while (n-- != 0) {
printf("byte = 0x%x\n", *(unsigned char *)pointer);
pointer++;
}
return 0;
}
/* END new.c */

I see no problem.
I don't understand what alignment problems
you think that there can be.

pointer = (char*)((unsigned)(char*)&object + 2)
points into the middle of a byte and is not a valid value for a pointer.
Undefined, but for some reason implementation might allow it.

Could there be any conflict with the Standard? (I'm asking, I'm not
completely sure myself.)

Perhaps my use of the word "alignment" was an abuse. I read
now in 3.2 that the Standard defines alignment only with respect
to byte-resolution, where I rather meant sub-byte. I saw a similarity
in that as you can access an object as int for only specific (aligned)
values of int*, in the same manner you can access (in my example)
an object as type char only for specific values of char*.
 
P

pete

S.Tobias wrote:
Since void* does not point to any object, is a "free pointer",
the Standard must specify that the void* values which are valid
for char*, are also valid for void*, otherwise undefined. And
this is what a programmer must be concerned about.

void* can hold the address of any byte of any object, just like char*.

N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.

6.2.5 Types
[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.
 
S

S.Tobias

void* can hold the address of any byte of any object, just like char*.

And which address void* in my example implementation cannot hold?

Valid int* values are determined (among others) by int type object
alignment requirements; char* - by char alignment, void* - by what?
By void object alignment? It doesn't make sense. Therefore
we have to set alignment requirements for values same as in char*.

(Note, that here I'm using the word valid/invalid not in the sense
of in/valid values (like trap representation), but in the sense
of un/defined behaviour. Ie. use of invalid pointer is undefined,
but the Standard does not forbid an implementation to define it.)
N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.

#7 adds to this provisions for alignment requirements. If you convert a
char* to an int*, and the pointer is not aligned for int, the behaviour
is undefined. The implementation might abort on the very moment of
attempt of such conversion, without even completing it.

Similarly, when you convert, say, an int* to void*, how do you know
that the result fulfills alignment requirements? Or when you convert
an integer to void*? When is the implementation allowed to abort
and when not?

My hypothesis is that in 6.2.5#26 the Standard formulates these
alignment requirements for (values of) void*. The implementation
is not allowed to abort when the result is aligned to type char,
otherwise it may.

At the same time it does not forbid the implementation to allow other
pointer values (eg. sub-byte resolution), it's just that it's undefined,
ie. outside the domain of interest of the Standard.
6.2.5 Types (6.2.5#26 in the Std)
[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.
^^^^^^^^^^^^^^^^^^^^^^

And this is what this sub-sub-subdiscussion was about when you asked
your question: whether "alignment requirements" refers to the values
of the pointer (or, to what the pointer points to), or to the pointer
object itself. I try to prove that talking at this point of the values
of type void* is not nonsensical (it is not a proof by itself what the
Standard actually means there, though). Others think it refers to the
objects of type void*, but it is still not clear why. (I have to yet
think over Keith's example program closely.)

===

And one more thought concerning nomenclature, which I think is pretty
obvious, but might be useful to express:

Types have "alignment properties" which impose "alignment requirements"
on pointers to them (ie. what values they can hold, or how the values
can be used).

(Disclaimer: with the above remark I'm not trying to prove anything;
in fact if I did, it would act against my hypothesis. I think that the
Standard's use of words is sloppy and I feel it's good to straighten
things up sometimes.)
 
P

pete

S.Tobias said:
And which address void* in my example implementation cannot hold?

I don't understand your question.
Valid int* values are determined (among others) by int type object
alignment requirements; char* - by char alignment, void* - by what?
By void object alignment? It doesn't make sense. Therefore
we have to set alignment requirements for values same as in char*.

(Note, that here I'm using the word valid/invalid not in the sense
of in/valid values (like trap representation), but in the sense
of un/defined behaviour. Ie. use of invalid pointer is undefined,
but the Standard does not forbid an implementation to define it.)
N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.
Similarly, when you convert, say, an int* to void*, how do you know
that the result fulfills alignment requirements?

The standard says so.
You must be reading 6.3.2.3 differently from the way that I read it.
Or when you convert
an integer to void*?

Conversion between pointers and integers is implementation defined.
There's nothing in the standard preventing
the addresses of four consecutive bytes
from converting to three odd numbers and an even one.
 
S

S.Tobias

I don't understand your question.

I asked because I didn't understand where to apply your statement to.
Perhaps, never mind.

N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.
Similarly, when you convert, say, an int* to void*, how do you know
that the result fulfills alignment requirements?
The standard says so.
Where?

You must be reading 6.3.2.3 differently from the way that I read it.

I think that the difference between our reading of 6.3.2.3 may be
that you might assume that #1 demands that conversions to and from
void* must always succede. IMO if that were the case, then all
conversions from void* to unaligned int* would have to complete
without a cough. I think this is not what the Standard requires.

#7 adds alignment provisions, and does not exclude void* types.

(In fact, I don't see why #1 is even neccessary. Or am I wrong?)
Conversion between pointers and integers is implementation defined.
There's nothing in the standard preventing
the addresses of four consecutive bytes
from converting to three odd numbers and an even one.

But if the implementation wishes to map integers exactly into pointers
and documents it so, then after conversion the Standard does apply.
 
P

pete

S.Tobias said:
I don't understand your question.

I asked because I didn't understand where to apply your statement to.
Perhaps, never mind.
N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.
Similarly, when you convert, say, an int* to void*, how do you know
that the result fulfills alignment requirements?
The standard says so.
Where?

You must be reading 6.3.2.3 differently from the way that I read it.

I think that the difference between our reading of 6.3.2.3 may be
that you might assume that #1 demands that conversions to and from
void* must always succede. IMO if that were the case, then all
conversions from void* to unaligned int*
would have to complete
without a cough. I think this is not what the Standard requires.

If you have an unaligned int*, then you are invoking
undefined behavior and you code is no longer C code.
The rules don't apply after that.
(In fact, I don't see why #1 is even neccessary.

That doesn't prove that you don't understand it, but it's a clue.
 
S

S.Tobias

pete said:
S.Tobias wrote:
If you have an unaligned int*, then you are invoking
undefined behavior and you code is no longer C code.
The rules don't apply after that.

int *ip;
char *cp;
void *vp;

cp = malloc(2 * sizeof(int));
cp++; //defined
vp = cp; //defined
ip = vp; //???
That doesn't prove that you don't understand it, but it's a clue.

Maybe I don't. Would you, please, care to explain it to me.
 
P

pete

S.Tobias said:
int *ip;
char *cp;
void *vp;

cp = malloc(2 * sizeof(int));
cp++; //defined
vp = cp; //defined
ip = vp; //???

Assuming that sizeof(int) is greater than one,
ip = vp;
is not defined.
 
P

pete

S.Tobias said:
Which point in the Std did you apply to explain this?

It would be from C89
C89 Last public draft

3.3.4 Cast operators

A pointer to an object or incomplete type may be converted to a
pointer to a different object type or a different incomplete type.
The resulting pointer might not be valid if it is improperly
aligned for the type pointed to.
 
P

pete

pete said:
It would be from C89
C89 Last public draft

3.3.4 Cast operators

A pointer to an object or incomplete type may be converted to a
pointer to a different object type or a different incomplete type.
The resulting pointer might not be valid if it is improperly
aligned for the type pointed to.

N869
6.3.2.3 Pointers
[#7] A pointer to an object or incomplete type may be
converted to a pointer to a different object or incomplete
type. If the resulting pointer is not correctly aligned
for the pointed-to type, the behavior is undefined.
 
S

S.Tobias

N869
6.3.2.3 Pointers
[#7] A pointer to an object or incomplete type may be
converted to a pointer to a different object or incomplete
type. If the resulting pointer is not correctly aligned
for the pointed-to type, the behavior is undefined.

Now, why do you think (again, I mean C&V) that a reverse conversion
must _always_ work:
int *ip;
void *vp;
ip = ...; //assume valid pointer
vp = ip;
 
P

pete

S.Tobias said:
N869
6.3.2.3 Pointers
[#7] A pointer to an object or incomplete type may be
converted to a pointer to a different object or incomplete
type. If the resulting pointer is not correctly aligned
for the pointed-to type, the behavior is undefined.

Now, why do you think (again, I mean C&V) that a reverse conversion
must _always_ work:
int *ip;
void *vp;
ip = ...; //assume valid pointer
vp = ip;

Because, according to the requoted standard text,
ip == vp
is guaranteed to be true after that.

(C&V, again)

N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.
 
S

S.Tobias

pete said:
S.Tobias said:
pete said:
pete wrote:

S.Tobias wrote:

S.Tobias wrote:

S.Tobias wrote:

int *ip;
char *cp;
void *vp;

cp = malloc(2 * sizeof(int));
cp++; //defined
vp = cp; //defined
ip = vp; //???

Assuming that sizeof(int) is greater than one,
ip = vp;
is not defined.

Why?

Because vp holds an address which is not aligned for type int.

Which point in the Std did you apply to explain this?

It would be from C89
C89 Last public draft

3.3.4 Cast operators

A pointer to an object or incomplete type may be converted to a
pointer to a different object type or a different incomplete type.
The resulting pointer might not be valid if it is improperly
aligned for the type pointed to.
N869
6.3.2.3 Pointers
[#7] A pointer to an object or incomplete type may be
converted to a pointer to a different object or incomplete
type. If the resulting pointer is not correctly aligned
for the pointed-to type, the behavior is undefined.

Now, why do you think (again, I mean C&V) that a reverse conversion
must _always_ work:
int *ip;
void *vp;
ip = ...; //assume valid pointer
vp = ip;
Because, according to the requoted standard text,
ip == vp
is guaranteed to be true after that.
(C&V, again)
N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.

1. Why do you think that #7 does not apply this time?

2. Why #1 does not apply to void* -> int* conversion?

What are the rules by which you choose which point applies to what
conversion type?
 
D

Dan Pop

In said:
pete said:
S.Tobias said:
pete wrote:

S.Tobias wrote:

S.Tobias wrote:

S.Tobias wrote:

int *ip;
char *cp;
void *vp;

cp = malloc(2 * sizeof(int));
cp++; //defined
vp = cp; //defined
ip = vp; //???

Assuming that sizeof(int) is greater than one,
ip = vp;
is not defined.

Why?

Because vp holds an address which is not aligned for type int.

Which point in the Std did you apply to explain this?

It would be from C89
C89 Last public draft

3.3.4 Cast operators

A pointer to an object or incomplete type may be converted to a
pointer to a different object type or a different incomplete type.
The resulting pointer might not be valid if it is improperly
aligned for the type pointed to.

N869
6.3.2.3 Pointers
[#7] A pointer to an object or incomplete type may be
converted to a pointer to a different object or incomplete
type. If the resulting pointer is not correctly aligned
for the pointed-to type, the behavior is undefined.

Now, why do you think (again, I mean C&V) that a reverse conversion
must _always_ work:
int *ip;
void *vp;
ip = ...; //assume valid pointer
vp = ip;
Because, according to the requoted standard text,
ip == vp
is guaranteed to be true after that.
(C&V, again)
N869
6.3.2.3 Pointers
[#1] A pointer to void may be converted to or from a pointer
to any incomplete or object type. A pointer to any
incomplete or object type may be converted to a pointer to
void and back again; the result shall compare equal to the
original pointer.

1. Why do you think that #7 does not apply this time?

Because the standard says so: character and void pointer values have
no alignment restrictions. Therefore, when converting something to
pointer to void, the resulting value is, by definition, correctly aligned.
2. Why #1 does not apply to void* -> int* conversion?

It does. But #7 applies too. There is no contradiction between the two.
#1 says that you can do the conversion and #7 says what happens if the
original pointer value was not properly aligned for the type of the result
of the conversion.
What are the rules by which you choose which point applies to what
conversion type?

The rest of the standard. Unfortunately, the standard is very poorly
written as a reference document: you can't only read the paragraph(s)
of immediate interest and expect to get a complete picture of the issue.

Dan
 
S

S.Tobias

Which, being a C++ compiler extension is certainly topical here, right?

I took the first plausible definition I found. C++ is not topical here,
but C++ shares many ideas with C. I thought the definition in above
document was not C++ specific. Anonymous structures aren't topical
here either. I was casually interested, since someone mentioned them.
I think the above example you provided is called "unnamed structure".
 

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,774
Messages
2,569,598
Members
45,149
Latest member
Vinay Kumar Nevatia0
Top