what's the size of type char foo[3] ?

I

Ike Naar

James Dow Allen said:
cp.c could be fixed with, for example :)-) )
char xbuffer[512+2];

i would write something as:
double dbuffer[512/sizeof(double)];
/* suppose sizeof(double)=2^n < 512
and double aligned >= 4chars
if one know that double has to be 64bits for standard
should be ok for me
*/
char *buffer;
buffer=(char*) dbuffer;
#define buffer (xbuffer + (2&(int)xbuffer))

Or use malloc to allocate the buffer (the return value
of malloc is properly aligned for any type).

But it seems the wrong approach to "fix" cp.c to work around the
quirks of a device driver. What if another device driver is installed
that requires 512-byte alignment? Fix cp.c again? What if cat or dd
is used instead of cp? Fix cat.c and dd.c as well?
 
J

James Dow Allen

I have to agree with cp's maintainer. I don't see how you can call (3)
or (4) a "bug-like feature", much less a bug.

I agree with most of the comments posted in response to
my "amusing true story." I think that for cc to enforce
4-byte alignment on large buffers with "round sizes" might
be a slight performance boost independent of any driver
bug, but I might be reluctant to make such a change due to
paranoia about unforeseen consequences.

And I agree that "bug-like feature" was a very poor
phrasing. I wanted a better phrasing, but didn't
spend more than 2 seconds trying to think of one.

And I might agree that "'cp' did nothing wrong", but for
cp's maintainer to refuse to make this simple change seems
inexplicable(*). Even ignoring that it bypasses the bug,
an aligned buffer is going to get better performance.
The mmap() usage was a recent change, so the potentially
misaligned
char buffer[512];
had presumably been used for all files previously.
(My memory is fuzzy. Buffer-size *might* have been some
other power-of-two, e.g. 4096.) A misaligned buffer
is going to give poorer performance than an aligned buffer
even if the kernel is just doing a memcpy()-type operation
from its own aligned buffer.

Efficiencies one doesn't bother with normally *should*
be of concern when writing a standard utility like 'cp.'

(* - The company needed paperwork and approvals for all
changes to existing programs; this may have affected
willingness to change.)
In a similar situation, I would use dd instead of cp. I don't know if
that would help in this case, though. I wonder if dd worries about
buffer alignment...

IIRC, 'dd' (unlike 'cp' and 'cat') did not use mmap() in any
case, but otherwise I don't recall its coding: Its behavior
was irrelevant to me. Please note that I didn't "need"
cp to examine disk labels. :) Instead I thought the bug
should be circumvented before a customer, whether doing
something silly or not, found it.

James
 
S

Shao Miller

Francois Grieu said:
I am wondering if (on a conforming hosted implementation of C99)
the following program is guaranteed to output: 3 3

Specifically, I'm afraid that there could be some padding,
either for type foo, or variable bar.

#include<stdio.h>
typedef char foo[3];
int main(void) {
foo bar;
printf("%u %u\n",(unsigned)sizeof(foo),(unsigned)sizeof bar);
return 0;
}

I was going to say "yes" -- sizeof(char) is 1 and arrays can't have any
padding between the elements -- but then I found I could not, at first
reading, rule out arrays having padding after the last element. It
would be daft, of course, but I can't see why it is not permitted.

I would say your are safe to assume that such things do not occur. The
widely used idiom: sizeof array / sizeof *array relies on it, for one
thing.

Not just an idiom. C99's 6.5.3.4p6, though an example, doesn't say
"sometimes" anywhere.
 
S

Shao Miller

I am wondering if (on a conforming hosted implementation of C99)
the following program is guaranteed to output: 3 3

Specifically, I'm afraid that there could be some padding,
either for type foo, or variable bar.

#include<stdio.h>
typedef char foo[3];
int main(void) {
foo bar;
printf("%u %u\n",(unsigned)sizeof(foo),(unsigned)sizeof bar);
return 0;
}

I just saw a related question in another C-devoted forum, recently. It
was slightly different: "How do I know that '(char *) &bar == (char *)
bar' ?"

Well in C99's 6.5.9, paragraphs 6 and 7 might help.

P6 suggests that an object can have a sub-object at its beginning. It
would seem odd to consider the first element of an array as not
constituting the sub-object at the beginning of an array.

P7 suggests that an object that's not an element of an array be treated
the same as an array with one element, which suggests that at least
'type[1]' has no initial padding. It'd seem odd if a greater count of
elements granted initial padding.

Then there's 'calloc'...

void * ptr = calloc(42, sizeof (int));
int * ip = ptr;
int (* ap)[42] = ptr;

It'd seem odd if 'calloc' had to allocate extra memory just in case you
might access the memory via '*ap' instead of 'ip'. It'd seem to
complicate alignment requirements.
 
T

Tim Rentsch

Ben Bacarisse said:
Francois Grieu said:
I am wondering if (on a conforming hosted implementation of C99)
the following program is guaranteed to output: 3 3

Specifically, I'm afraid that there could be some padding,
either for type foo, or variable bar.

#include <stdio.h>
typedef char foo[3];
int main(void) {
foo bar;
printf("%u %u\n",(unsigned)sizeof(foo),(unsigned)sizeof bar);
return 0;
}

I was going to say "yes" -- sizeof(char) is 1 and arrays can't have any
padding between the elements -- but then I found I could not, at first
reading, rule out arrays having padding after the last element. It
would be daft, of course, but I can't see why it is not permitted.

I would say your are safe to assume that such things do not occur. The
widely used idiom: sizeof array / sizeof *array relies on it, for one
thing.

FWIW, I raised exactly this question in 2005 in comp.std.c. The
thread subject was 'sizeof(T[N]) == (N) * sizeof(T)?', if anyone
is interested.
 
T

Tim Rentsch

Ben Bacarisse said:
Barry Schwarz said:
I am wondering if (on a conforming hosted implementation of C99)
the following program is guaranteed to output: 3 3

Specifically, I'm afraid that there could be some padding,
either for type foo, or variable bar.

#include <stdio.h>
typedef char foo[3];
int main(void) {
foo bar;
printf("%u %u\n",(unsigned)sizeof(foo),(unsigned)sizeof bar);
return 0;
}

I was going to say "yes" -- sizeof(char) is 1 and arrays can't have any
padding between the elements -- but then I found I could not, at first
reading, rule out arrays having padding after the last element. It
would be daft, of course, but I can't see why it is not permitted.

I would say your are safe to assume that such things do not occur. The
widely used idiom: sizeof array / sizeof *array relies on it, for one
thing.

Does changing the definition of bar to
foo bar[2]
and then applying 6.2.5-20 and 6.5.2.1-4 effectively eliminate the
possibility of "end of array padding"?

I don't think so. Both of those apply equally to

struct { char a[3]; } sa[2];

and we know that the sizeof sa[0] need not be 3.
How about 6.5.3.4-3 which discusses sizeof applied to arrays? It
mentions internal and trailing padding for structure and union types
but not for arrays.

Yes, that's enough for me, though it's a shame it's a demonstration by
omission.
How about footnote 94 which talks about sub-arrays being adjacent?

For me, no. If the supposed padding is part of the array (like it is
with a struct) the arrays are still adjacent.

If you read the normative text in 6.5.9 p6 (the footnoted paragraph)
in conjunction with the footnote, I think you'll agree that the
two together preclude the possibility of any trailing padding.
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse said:
Barry Schwarz said:
On Wed, 22 Feb 2012 14:06:55 +0000, Ben Bacarisse


I am wondering if (on a conforming hosted implementation of C99)
the following program is guaranteed to output: 3 3

Specifically, I'm afraid that there could be some padding,
either for type foo, or variable bar.

#include <stdio.h>
typedef char foo[3];
int main(void) {
foo bar;
printf("%u %u\n",(unsigned)sizeof(foo),(unsigned)sizeof bar);
return 0;
}

I was going to say "yes" -- sizeof(char) is 1 and arrays can't have any
padding between the elements -- but then I found I could not, at first
reading, rule out arrays having padding after the last element. It
would be daft, of course, but I can't see why it is not permitted.

I would say your are safe to assume that such things do not occur. The
widely used idiom: sizeof array / sizeof *array relies on it, for one
thing.

Does changing the definition of bar to
foo bar[2]
and then applying 6.2.5-20 and 6.5.2.1-4 effectively eliminate the
possibility of "end of array padding"?

I don't think so. Both of those apply equally to

struct { char a[3]; } sa[2];

and we know that the sizeof sa[0] need not be 3.
How about 6.5.3.4-3 which discusses sizeof applied to arrays? It
mentions internal and trailing padding for structure and union types
but not for arrays.

Yes, that's enough for me, though it's a shame it's a demonstration by
omission.
How about footnote 94 which talks about sub-arrays being adjacent?

For me, no. If the supposed padding is part of the array (like it is
with a struct) the arrays are still adjacent.

If you read the normative text in 6.5.9 p6 (the footnoted paragraph)
in conjunction with the footnote, I think you'll agree that the
two together preclude the possibility of any trailing padding.

I'm not getting it. Can you say more?

In my head, I have this picture where a 3-element int array is padded to
be the size of a 4-element one:

int A[2][3], *p1 = A[0] + 3, *p2 = A[1];

+----+----+----+----+----+----+----+----+
A: | | | |XXXX| | | |XXXX|
+----+----+----+----+----+----+----+----+
^ ^
p1 p2

6.5.9 p6 says that p1 and p2 don't compare equal but I don't see why
they must. Presumably this is a case where the "different array" of
6.5.9 p6 does *not* "happen to follow" the first. The footnote gives
permission for p1 and p2 to be equal but, unless I'm misreading it, I
don't see that it requires it.
 
K

Keith Thompson

Tim Rentsch said:
If you read the normative text in 6.5.9 p6 (the footnoted paragraph)
in conjunction with the footnote, I think you'll agree that the
two together preclude the possibility of any trailing padding.

I don't think so.

Here's the paragraph from N1570:

Two pointers compare equal if and only if both are null pointers,
both are pointers to the same object (including a pointer to an
object and a subobject at its beginning) or function, both are
pointers to one past the last element of the same array object,
or one is a pointer to one past the end of one array object and
the other is a pointer to the start of a different array object
that happens to immediately follow the first array object in
the address space.

And here's the footnote:

Two objects may be adjacent in memory because they are adjacent
elements of a larger array or adjacent members of a structure
with no padding between them, or because the implementation
chose to place them so, even though they are unrelated. If prior
invalid pointer operations (such as accesses outside array
bounds) produced undefined behavior, subsequent comparisons
also produce undefined behavior.

The footnote describes circumstances in which two objects *may
be* adjacent in memory. I don't believe it implies that adjacent
elements of a larger array *must be* adjacent in memory.

I think the intent is that consecutive array elements must be
adjacent in memory, but I don't think this footnote is enough to
prove that intent.
 
T

Tim Rentsch

Keith Thompson said:
I don't think so.

Here's the paragraph from N1570:

Two pointers compare equal if and only if both are null pointers,
both are pointers to the same object (including a pointer to an
object and a subobject at its beginning) or function, both are
pointers to one past the last element of the same array object,
or one is a pointer to one past the end of one array object and
the other is a pointer to the start of a different array object
that happens to immediately follow the first array object in
the address space.

And here's the footnote:

Two objects may be adjacent in memory because they are adjacent
elements of a larger array or adjacent members of a structure
with no padding between them, or because the implementation
chose to place them so, even though they are unrelated. If prior
invalid pointer operations (such as accesses outside array
bounds) produced undefined behavior, subsequent comparisons
also produce undefined behavior.

The footnote describes circumstances in which two objects *may
be* adjacent in memory. I don't believe it implies that adjacent
elements of a larger array *must be* adjacent in memory.

I think the intent is that consecutive array elements must be
adjacent in memory, but I don't think this footnote is enough to
prove that intent.

I wouldn't call it intent; more like unconscious assumption.
 
T

Tim Rentsch

Ben Bacarisse said:
Tim Rentsch said:
Ben Bacarisse said:
On Wed, 22 Feb 2012 14:06:55 +0000, Ben Bacarisse


I am wondering if (on a conforming hosted implementation of C99)
the following program is guaranteed to output: 3 3

Specifically, I'm afraid that there could be some padding,
either for type foo, or variable bar.

#include <stdio.h>
typedef char foo[3];
int main(void) {
foo bar;
printf("%u %u\n",(unsigned)sizeof(foo),(unsigned)sizeof bar);
return 0;
}

I was going to say "yes" -- sizeof(char) is 1 and arrays can't have any
padding between the elements -- but then I found I could not, at first
reading, rule out arrays having padding after the last element. It
would be daft, of course, but I can't see why it is not permitted.

I would say your are safe to assume that such things do not occur. The
widely used idiom: sizeof array / sizeof *array relies on it, for one
thing.

Does changing the definition of bar to
foo bar[2]
and then applying 6.2.5-20 and 6.5.2.1-4 effectively eliminate the
possibility of "end of array padding"?

I don't think so. Both of those apply equally to

struct { char a[3]; } sa[2];

and we know that the sizeof sa[0] need not be 3.

How about 6.5.3.4-3 which discusses sizeof applied to arrays? It
mentions internal and trailing padding for structure and union types
but not for arrays.

Yes, that's enough for me, though it's a shame it's a demonstration by
omission.

How about footnote 94 which talks about sub-arrays being adjacent?

For me, no. If the supposed padding is part of the array (like it is
with a struct) the arrays are still adjacent.

If you read the normative text in 6.5.9 p6 (the footnoted paragraph)
in conjunction with the footnote, I think you'll agree that the
two together preclude the possibility of any trailing padding.

I'm not getting it. Can you say more?

In my head, I have this picture where a 3-element int array is padded to
be the size of a 4-element one:

int A[2][3], *p1 = A[0] + 3, *p2 = A[1];

+----+----+----+----+----+----+----+----+
A: | | | |XXXX| | | |XXXX|
+----+----+----+----+----+----+----+----+
^ ^
p1 p2

6.5.9 p6 says that p1 and p2 don't compare equal but I don't see why
they must. Presumably this is a case where the "different array" of
6.5.9 p6 does *not* "happen to follow" the first. The footnote gives
permission for p1 and p2 to be equal but, unless I'm misreading it, I
don't see that it requires it.

My point was about the parallel constructions in p6 (the text of
which Keith Thompson courteously provided in his response). In
one case there is a reference to "one past the last element of an
array object", and in the other a reference to "one past the end
of one array object". Because of the phrasing I think it shows
an unconscious assumption that these two are synonymous: one
past the last element of an array is the same as one past the
whole array, and therefore that there is no padding. This also
explains why the requirement isn't stated explicitly - because
the assumption was made without conscious thought, it never
occurred to anyone to state it.
 
B

Ben Bacarisse

My point was about the parallel constructions in p6 (the text of
which Keith Thompson courteously provided in his response). In
one case there is a reference to "one past the last element of an
array object", and in the other a reference to "one past the end
of one array object". Because of the phrasing I think it shows
an unconscious assumption that these two are synonymous: one
past the last element of an array is the same as one past the
whole array, and therefore that there is no padding. This also
explains why the requirement isn't stated explicitly - because
the assumption was made without conscious thought, it never
occurred to anyone to state it.

Right. I see what you mean now.
 
R

Robert Miles

Dividing the array size by the element size to get the length would
still work if the amount of padding at the end of an array is less than
the size of an element.

Could this be saying that if padding is placed at the end of the array,
sizeof() must not consider it part of the array?

Robert Miles
 
K

Kaz Kylheku

Could this be saying that if padding is placed at the end of the array,
sizeof() must not consider it part of the array?

If it's not in sizeof, it's not part of the type, period.

There may be bytes between objects which are the members of a structure. There
may be space between variables that are located in storage next to each other.

The space after an object A, before object B at the higher address,
is not related to the type of object A. It most likely exists for the
sake of correct or efficient alignment of object B.
 

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

Forum statistics

Threads
474,079
Messages
2,570,575
Members
47,207
Latest member
HelenaCani

Latest Threads

Top