473,549 Members | 2,531 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Pre-offsetof() question


As far as I know, C89/C90 did not contain the
now-standard offsetof() macro.

Did C89 mandate that structs had to have a consistent
layout? For example, consider the typical layout of
the following structure:

struct weird
{
int x; /* sizeof(int)==4 here */
double y; /* sizeof(double)= =8 here */
int z;
};

Now, let's suppose that the target architecture has typical
80x86 alignment requirements, where 'int' aligns on 4-byte
boundaries and 'double' on 8-byte boundaries.
A C99 compiler might produce a layout that looked like
this:

|_x__|####|___y ____|_z__|####|

sizeof (struct weird) == 24 bytes
But could a C89, pre-offsetof() compiler decide to make
the layout of the struct vary, like this:

|_x__|####|___y ____|_z__| on 8-byte alignment

|_x__|___y____| ####|_z__| on 4-byte alignment

sizeof (struct weird) == 20 bytes
Note that the relative ordering of the members is
preserved; each 'struct weird' has the same size in
bytes; and all objects are properly aligned for their
type. But the "weird" ordering has saved us 4 bytes
per structure!

Does C89 allow this, or is it disallowed by something
in that standard? If so, what?

TIA,
-Arthur

Nov 13 '05 #1
6 2182
"Arthur J. O'Dwyer" wrote:

As far as I know, C89/C90 did not contain the
now-standard offsetof() macro.
Full stop: C89 invented the <stddef.h> header, and specified
that it must provide offsetof().
Did C89 mandate that structs had to have a consistent
layout? For example, consider the typical layout of
the following structure:

struct weird
{
int x; /* sizeof(int)==4 here */
double y; /* sizeof(double)= =8 here */
int z;
};

Now, let's suppose that the target architecture has typical
80x86 alignment requirements, where 'int' aligns on 4-byte
boundaries and 'double' on 8-byte boundaries.
A C99 compiler might produce a layout that looked like
this:

|_x__|####|___y ____|_z__|####|

sizeof (struct weird) == 24 bytes

But could a C89, pre-offsetof() compiler decide to make
the layout of the struct vary, like this:

|_x__|####|___y ____|_z__| on 8-byte alignment

|_x__|___y____| ####|_z__| on 4-byte alignment

sizeof (struct weird) == 20 bytes

Note that the relative ordering of the members is
preserved; each 'struct weird' has the same size in
bytes; and all objects are properly aligned for their
type. But the "weird" ordering has saved us 4 bytes
per structure!

Does C89 allow this, or is it disallowed by something
in that standard? If so, what?


No version of the Standard describes what alignments
are to be enforced. However, the rules for compatibility
of types guarantee that the same struct type will have the
same arrangement of padding bytes in all translation units.

Could this arrangement be different depending on flags
calling for different "strictness es" of alignment? Yes, of
course -- but this isn't a contradiction, because using a
different set of compiler flags gives you a different
implementation of C, and the Standard makes no requirement
that translation units compiled by different implementations
must interoperate.

By the way, note that your 8-byte alignment example is
faulty. If a double must be aligned to an 8-byte boundary,
the sizeof a struct containing a double must be a multiple
of 8 bytes. Otherwise, you would not be able to malloc()
an array of two such structs:

struct weird *p = malloc(2 * sizeof *p); // assume 40

0 4 8 16 20 24 28 36 40
|_x__|####|___y ____|_z__|_x__| ####|___y____|_ z__|
^ ^
| |
p p+1

Note that (p+1)->y is mis-aligned.

--
Er*********@sun .com
Nov 13 '05 #2

On Mon, 6 Oct 2003, Eric Sosman wrote:

Arthur J. O'Dwyer wrote:

As far as I know, C89/C90 did not contain the
now-standard offsetof() macro.
Full stop: C89 invented the <stddef.h> header, and specified
that it must provide offsetof().


Oops. I guess the point is moot, then.
struct weird
{
int x; /* sizeof(int)==4 here */
double y; /* sizeof(double)= =8 here */
int z;
}; But could a C89, pre-offsetof() compiler decide to make
the layout of the struct vary, like this:

|_x__|####|___y ____|_z__| on 8-byte alignment

|_x__|___y____| ####|_z__| on 4-byte alignment

sizeof (struct weird) == 20 bytes

Note that the relative ordering of the members is
preserved; each 'struct weird' has the same size in
bytes; and all objects are properly aligned for their
type. But the "weird" ordering has saved us 4 bytes
per structure!


No version of the Standard describes what alignments
are to be enforced. However, the rules for compatibility
of types guarantee that the same struct type will have the
same arrangement of padding bytes in all translation units.
How so? (Obviously, the existence of 'offsetof' assumes
that all 'struct weird's will have the same layout -- but
would that rule be explicitly stated anywhere if 'offsetof'
didn't exist?)

By the way, note that your 8-byte alignment example is
faulty. If a double must be aligned to an 8-byte boundary,
the sizeof a struct containing a double must be a multiple
of 8 bytes.
Why? (Other than the paragraph which in N869 is 7.17#3,
that is.)
Otherwise, you would not be able to malloc()
an array of two such structs:

struct weird *p = malloc(2 * sizeof *p); // assume 40

0 4 8 16 20 24 28 36 40
|_x__|####|___y ____|_z__|_x__| ####|___y____|_ z__|
Ah -- your diagram is incorrect. :-) The "correct" layout
for two optimized (but apparently non-conforming) 'struct
weird's is:
0 4 8 16 20 24 28 36 40 |_x__|####|___y ____|_z__|_x__| ___y____|####|_ z__| ^ ^
| |
p p+1

Note that (p+1)->y is mis-aligned.


Not anymore -- not if we remove 7.17#3. I had thought
that C89 didn't have offsetof(); apparently I was
wrong. Never mind, then.

-Arthur

Nov 13 '05 #3
"Arthur J. O'Dwyer" wrote:

On Mon, 6 Oct 2003, Eric Sosman wrote:

By the way, note that your 8-byte alignment example is
faulty. If a double must be aligned to an 8-byte boundary,
the sizeof a struct containing a double must be a multiple
of 8 bytes.


Why? (Other than the paragraph which in N869 is 7.17#3,
that is.)
Otherwise, you would not be able to malloc()
an array of two such structs:

struct weird *p = malloc(2 * sizeof *p); // assume 40

0 4 8 16 20 24 28 36 40
|_x__|####|___y ____|_z__|_x__| ####|___y____|_ z__|


Ah -- your diagram is incorrect. :-) The "correct" layout
for two optimized (but apparently non-conforming) 'struct
weird's is:
0 4 8 16 20 24 28 36 40

|_x__|####|___y ____|_z__|_x__| ___y____|####|_ z__|
^ ^
| |
p p+1

Note that (p+1)->y is mis-aligned.


Not anymore -- not if we remove 7.17#3. I had thought
that C89 didn't have offsetof(); apparently I was
wrong. Never mind, then.


Aha! Finally, the mystery of why offsetof intruded itself
into an apparently unrelated question becomes clear. Just to
be sure I've understood you: You're wondering whether different
instances of struct weird in the same program could arrange
their padding differently. Clearly, this cannot be the case
if offsetof(struct weird, y) is single-valued.

But even without offsetof I think you can rule out such
shenanigans. True, direct assignment of struct objects might
perhaps be clever enough to play games. But memcpy() must
also work:

struct weird *p = malloc(2 * sizeof *p);
p[0].x = ...; p[0].y = ...; p[0].z = ...;
memcpy (p+1, p, sizeof *p);
assert (p[1].x == p[0].x);
assert (p[1].y == p[0].y); // the crucial point
assert (p[2].z == p[0].z);

Since memcpy() knows only the size of the data being copied
and nothing about the nature of the object those data bytes
represent, it cannot possibly know enough to "slide" the
`y' element while copying the bag of bytes from one place
to another. Similar remarks apply to realloc() and to
fwrite()/fread(), and to other type-oblivious ways of moving
data from place to place.

--
Er*********@sun .com
Nov 13 '05 #4

On Mon, 6 Oct 2003, Eric Sosman wrote:

Aha! Finally, the mystery of why offsetof intruded itself
into an apparently unrelated question becomes clear. Just to
be sure I've understood you: You're wondering whether different
instances of struct weird in the same program could arrange
their padding differently. Clearly, this cannot be the case
if offsetof(struct weird, y) is single-valued.
Yes! You've hit the nail on the head.
But even without offsetof I think you can rule out such
shenanigans. True, direct assignment of struct objects might
perhaps be clever enough to play games. But memcpy() must
also work:

struct weird *p = malloc(2 * sizeof *p);
p[0].x = ...; p[0].y = ...; p[0].z = ...;
memcpy (p+1, p, sizeof *p);
assert (p[1].x == p[0].x);
assert (p[1].y == p[0].y); // the crucial point
assert (p[2].z == p[0].z);


Yes, but *must* these 'assert(...)'s succeed? (Obviously
they needn't succeed if p[0].y is a trap representation,
or one of p[0],p[1] is volatile, for instance.)

Where does it say that

foo x = ...;
foo y = ...;
memcpy(&x, &y, sizeof (foo))
assert (x==y);

must necessarily succeed? I don't see anywhere, except perhaps
footnote 38 (which says that struct assignment may be done
"element-at-a-time or via memcpy"). And I don't think footnotes
are normative, even if the intent of the footnote were clearer.

-Arthur
[Remember, the whole question is moot.] ;-)

Nov 13 '05 #5
On Mon, 6 Oct 2003 19:08:06 -0400 (EDT), "Arthur J. O'Dwyer"
<aj*@nospam.and rew.cmu.edu> wrote in comp.lang.c:

On Mon, 6 Oct 2003, Eric Sosman wrote:

Aha! Finally, the mystery of why offsetof intruded itself
into an apparently unrelated question becomes clear. Just to
be sure I've understood you: You're wondering whether different
instances of struct weird in the same program could arrange
their padding differently. Clearly, this cannot be the case
if offsetof(struct weird, y) is single-valued.


Yes! You've hit the nail on the head.
But even without offsetof I think you can rule out such
shenanigans. True, direct assignment of struct objects might
perhaps be clever enough to play games. But memcpy() must
also work:

struct weird *p = malloc(2 * sizeof *p);
p[0].x = ...; p[0].y = ...; p[0].z = ...;
memcpy (p+1, p, sizeof *p);
assert (p[1].x == p[0].x);
assert (p[1].y == p[0].y); // the crucial point
assert (p[2].z == p[0].z);


Yes, but *must* these 'assert(...)'s succeed? (Obviously
they needn't succeed if p[0].y is a trap representation,
or one of p[0],p[1] is volatile, for instance.)

Where does it say that

foo x = ...;
foo y = ...;
memcpy(&x, &y, sizeof (foo))
assert (x==y);

must necessarily succeed? I don't see anywhere, except perhaps
footnote 38 (which says that struct assignment may be done
"element-at-a-time or via memcpy"). And I don't think footnotes
are normative, even if the intent of the footnote were clearer.

-Arthur
[Remember, the whole question is moot.] ;-)


What you missed is:

========
6.2.6 Representations of types

6.2.6.1 General

1 The representations of all types are unspecified except as stated in
this subclause.

2 Except for bit-fields, objects are composed of contiguous sequences
of one or more bytes, the number, order, and encoding of which are
either explicitly specified or implementation-defined.

3 Values stored in unsigned bit-fields and objects of type unsigned
char shall be represented using a pure binary notation.

4 Values stored in non-bit-field objects of any other object type
consist of n ´ CHAR_BIT bits, where n is the size of an object of that
type, in bytes. The value may be copied into an object of type
unsigned char [n] (e.g., by memcpy); the resulting set of bytes is
called the object representation of the value. Values stored in
bit-fields consist of m bits, where m is the size specified for the
bit-field. The object representation is the set of m bits the
bit-field comprises in the addressable storage unit holding it. Two
values (other than NaNs) with the same object representation compare
equal, but values that compare equal may have different object
representations .
========

From C99, and note the last sentence in paragraph 4.

Even without this, it would be impossible pass or return structures or
pointers to structures to functions in separate translation units if
an identical structure definition did not result in identically laid
out objects.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
Nov 13 '05 #6

On Tue, 7 Oct 2003, Jack Klein wrote:

Arthur J. O'Dwyer wrote:
On Mon, 6 Oct 2003, Eric Sosman wrote:

Aha! Finally, the mystery of why offsetof intruded itself
into an apparently unrelated question becomes clear. Just to
be sure I've understood you: You're wondering whether different
instances of struct weird in the same program could arrange
their padding differently. Clearly, this cannot be the case
if offsetof(struct weird, y) is single-valued.
Yes! You've hit the nail on the head.
But even without offsetof I think you can rule out such
shenanigans. True, direct assignment of struct objects might
perhaps be clever enough to play games. But memcpy() must
also work:
Where does it say that

foo x = ...;
foo y = ...;
memcpy(&x, &y, sizeof (foo))
assert (x==y);

must necessarily succeed? I don't see anywhere, except perhaps
footnote 38

What you missed is:

========
6.2.6 Representations of types

6.2.6.1 General

1 The representations of all types are unspecified except as stated in
this subclause.

2 Except for bit-fields, objects are composed of contiguous sequences
of one or more bytes, the number, order, and encoding of which are
either explicitly specified or implementation-defined.
Okay, no problems here. The "weird" layout can be defined easily
by the implementation.
3 Values stored in unsigned bit-fields and objects of type unsigned
char shall be represented using a pure binary notation.

4 Values stored in non-bit-field objects of any other object type
consist of n ´ CHAR_BIT bits, where n is the size of an object of that
type, in bytes. The value may be copied into an object of type
unsigned char [n] (e.g., by memcpy); the resulting set of bytes is
called the object representation of the value. Values stored in
bit-fields consist of m bits, where m is the size specified for the
bit-field. The object representation is the set of m bits the
bit-field comprises in the addressable storage unit holding it. Two
values (other than NaNs) with the same object representation compare
equal,
Okay, this is the part I assume you mean. Well,
<devil's-advocate>
what exactly does it mean for two structs to "compare equal"?
I mean, you can't use the == operator on structs, right? And if
we can only talk about member-by-member equality, well then we'll
have to consider a *member-by-member* memcpy -- which works fine!
</devil's-advocate>
but values that compare equal may have different object
representations .
========

From C99, and note the last sentence in paragraph 4.
(And not in N869, right?)
Even without this, it would be impossible pass or return structures or
pointers to structures to functions in separate translation units if
an identical structure definition did not result in identically laid
out objects.


Debatable. But irrelevant. ;-)
Remember, the "weird" layout is perfectly consistent between t.u.'s.
A compiler could say, "Okay, this struct is a candidate for
weirdification, " and generate appropriate code across all t.u.'s,
easily enough.

-Arthur
[Remember, still moot.]

P.S.-- As a small on-topic note, am I completely mistaken in my
prior belief that 'offsetof' was a relatively recent addition to
C? If so, why do we get so many variations on FAQ 2.14? :)
Nov 13 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
3697
by: Porthos | last post by:
Hi All, I'm building an XSL document that puts two types of information in a table dimension: preformatted data and data extracted from my XML document (see below) <table> <tr>
3
3780
Pre
by: Neal | last post by:
A few questions about pre... When presenting preformatted text using the white-space: pre; property/value, Opera renders long lines at small viewport widths as exiting the borders of the element, IE6 extends the element to contain the line. Both necessitate horizontal scrolling. 1) Is one considered incorrect, or are both fair...
7
5023
by: Roderik | last post by:
Hi, When I use <pre> inside my <td> cells, the text won't flow to a new line and the table gets to large in width. This will appear in Firefox this way, Internet Explorer will wrap the lines, like I want, by default. Any idea what I should define to make firefox wrap the text inside the pre? <table><tr><td><pre>this is unwrapped in...
17
25233
by: TheKeith | last post by:
Isn't there a style for preformatted text, instead of having to use the pre tags? Help would be appreciated--thanks.
1
4728
by: R0bert Nev1lle | last post by:
Here's my next IE challenge (or frustration). It deals with the overflow attribute. Overflow property was a challenge on my page since the page emulates position fixed for IE. The present scenario deals with the pre element. Sometimes the content in the pre container exceed the parent container's width. IE expands the parent containers...
9
5531
by: Eric Lindsay | last post by:
I can't figure how to best display little snippets of shell script using <pre>. I just got around to organising to bulk validate some of my web pages, and one of the problems occurs with Bash shell pieces like this: <pre><code> #!/bin/sh ftp -i -n ftp.server.com&lt; &lt;EOF user username password epsv4 cd /
14
3611
by: Schraalhans Keukenmeester | last post by:
I am building a default sheet for my linux-related pages. Since many linux users still rely on/prefer viewing textmode and unstyled content I try to stick to the correct html tags to pertain good readibility on browsers w/o css-support. For important notes, warnings etc I use the <pre> tag, which shows in a neat bordered box when viewed...
12
5556
by: Vadim Guchenko | last post by:
Hello. I'm using the following code: <html> <head> <style type="text/css"> pre {display: inline;} </style> </head>
2
1911
by: Mitoshima | last post by:
The pre-alpha version of Tic Tac Toe Plus, which is actually a Tic Tac Toe game, will be made available on Wed 27th. Your contribution is needed and will be appreciated as we would like persons to sample this version of the game and give their honest comments, whether good or bad, report errors and problems, or give any good idea that will...
11
3881
by: divya_rathore_ | last post by:
The code: int aaa = 100; printf("%d %d %d\n", --aaa, aaa, aaa--); printf("%d\n", aaa); prints: 99 100 100 98
0
7526
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7457
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7723
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
1
7483
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
6051
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5375
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5092
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
1
1949
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
0
771
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.