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

F

Francois Grieu

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;
}
 
S

Stefan Ram

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

z Specifies that a following d, i, o, u, x, or X
conversion specifier applies to a size_t

, so

printf( "%zu\n", sizeof( alpha ));

(untested).
 
B

Ben Bacarisse

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

Stefan Ram

Ben Bacarisse said:
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

It is said, »When applied to an operand that has array type,
the result is the total number of bytes in the array.«
in »6.5.3.4 The sizeof operator« of »ISO/IEC 9899:1999 (E)«.
 
S

Stephen Sprunk

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

True. One should not forget that the array elements themselves may
contain padding, but that is extremely unlikely in this case.

S
 
F

Francois Grieu

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.

Invoquing that idiom is an excellent idea. It is given in the standard
as 6.5.3.4 (6)
Another use of the sizeof operator is to compute the number of
elements in an array:
sizeof array / sizeof array[0]

Thus I'm ready to assume that after

char bot[3];

indeed sizeof(bot) is 3.


But does that tell us the size of the type foo or of the variable
bar [that would be the case if bar was an "array" in the sense
of 6.5.3.4 (6), but is it?
 
B

Ben Bacarisse

It is said, »When applied to an operand that has array type,
the result is the total number of bytes in the array.«
in »6.5.3.4 The sizeof operator« of »ISO/IEC 9899:1999 (E)«.

I don't think that helps. It does not say that the total number of
bytes in the array can't be a few more than the minimum required.

Two things do help. (1) Later in the same paragraph "trailing padding"
is explicitly referred to for struct types, so one can, I think, exclude
it for array types simply by the fact that it is *not* mentioned. (2)
The example in paragraph 6. Not normative by itself, but the intent is
made very clear.
 
B

Ben Bacarisse

Francois Grieu 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.

Invoquing that idiom is an excellent idea. It is given in the standard
as 6.5.3.4 (6)
Another use of the sizeof operator is to compute the number of
elements in an array:
sizeof array / sizeof array[0]

Yes, the intent is made 100% clear by that example.
Thus I'm ready to assume that after

char bot[3];

indeed sizeof(bot) is 3.


But does that tell us the size of the type foo or of the variable
bar [that would be the case if bar was an "array" in the sense
of 6.5.3.4 (6), but is it?

I can't see why not.
 
J

jacob navia

Le 22/02/12 14:24, Francois Grieu a écrit :
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;
}

The size is 3. Padding is of course there, but not in the array. Under
lcc-win the padding is inserted after the array, leaving a byte in the
stack unused, not a big deal this days.
 
B

BartC

jacob navia said:
Le 22/02/12 14:24, Francois Grieu a écrit :
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;
}

The size is 3. Padding is of course there, but not in the array. Under
lcc-win the padding is inserted after the array, leaving a byte in the
stack unused, not a big deal this days.

What about in: foo bar[100]; ?

All the compilers I tried showed sizeof(bar) to be 300, so no padding
between elements, yet to me it would seem useful to round each entry up to 4
bytes: that makes it possible to copy an entire 3-byte entry to another
using 32-bit instructions, all the entries start on a preferred alignment,
and index calculation is simpler.

(However I'm not sure I'd be happy about a foo[33] element rounded up to
64...)
 
B

Barry Schwarz

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.

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"?

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.

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

jacob navia

Le 22/02/12 15:06, Ben Bacarisse a écrit :
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.

Of course it is permitted. The padding bytes just aren't part of the
array!
 
B

Ben Bacarisse

Barry Schwarz 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.

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

Stefan Ram

Ben Bacarisse said:
I don't think that helps. It does not say that the total number of
bytes in the array can't be a few more than the minimum required.

There is:

»There may be unnamed padding at the end of a
structure or union.« 6.7.2.1p15, ISO/IEC 9899:1999 (E)

But no such license is given for an array.
 
B

Ben Bacarisse

There is:

»There may be unnamed padding at the end of a
structure or union.« 6.7.2.1p15, ISO/IEC 9899:1999 (E)

But no such license is given for an array.

Yes, as I've already said, I think that silence is the strongest
argument. That and the explicit example of dividing the array size by
the element size to get the length.
 
K

Keith Thompson

Ben Bacarisse said:
Yes, as I've already said, I think that silence is the strongest
argument. That and the explicit example of dividing the array size by
the element size to get the length.

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

Nick Keighley

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.

but in the case of a char array...
 
J

James Dow Allen

This discussion reminds me of a true story from 24 years ago that might
interest or amuse. I wanted to look at the label on a disk so adopted a
"minimum keystroke" solution:
cp /dev/rsd0b copy_of_label
^C
To my surprise, the data in 'copy' was scrambled, i.e. odd and even
shorts were swapped. (Or maybe I just got 'kernel panic.' After all
these years, I may be conflating two related stories. In any event the
'cp' did not do what it should.)

The error was quite repeatable: running 'cp' on any raw scsi partition
would exhibit the same problem with that release. I'll guess it wasn't
something users did a lot. :) And, every time 'cp' was recompiled
after minor changes it had a 50-50 chance of functioning correctly.

There were four bugs or bug-like features interacting:
(1) The SCSI controller hardware operated properly only on 4-byte
aligned buffer addresses.
(2) The SCSI driver neglected to cheeck for that alignment.
(3) The program cp.c (which used mmap() for most reads) did reads from
special devices with simply
char buffer[512];
read(infd, buffer, 512);
(4) The cc compiler, faced with a declaration like "char buffer[512]",
saw fit to guarantee 2-byte alignment, but not 4-byte alignment.

I thought this strange episode had instructive features. The clearest
bug might be (1), but it was more-or-less unfixable. Why make a
complicated hardware change to accomodate a yokel who reads disk-labels
with 'cp'? (2) was a blatant stupidity, but correcting it wouldn't
completely solve the problem: The yokel would still get IO_error,
though that is much better than scrambled data or kernel panic.

Neither (3) nor (4) were considered "bugs" -- both the compiler and cp.c
were doing that which they were allowed to do by specs. At the same
time, it seemed both simple and appropriate to fix the problem by
amending cp.c and/or the compiler.

cp.c could be fixed with, for example :)-) )
char xbuffer[512+2];
#define buffer (xbuffer + (2&(int)xbuffer))
And, it seemed possibly sound to add the following logic to the C
compiler:
/* If the character array size is a multiple of 512 , then
* force it to be at least 4-byte aligned unless the array is
* inside a structure. Any storage wastage will be quite small,
* and it's likely to boost performance at least slightly, as well
* as fixing bugs like 'cp /dev/rsd0b.'
*/

I was working as a contractor for a large company, and reported the
situation, through channels to the hardware group's ambassador to the
guru group. I wish I'd saved the e-mail he sent back. It was something
like this:
I have been to the mountaintop, and the following is
inscribed in stone:
The alignment requirement for character arrays is Two,
and Two is the alignment requirement for character arrays.

A fix for cp.c would take 2 minutes of coding labor (no, I wouldn't
really fix it as above) and several hours in the Bug Tracking and
Approval program. cp's maintainer was uninterested: his program "did
nothing wrong."

AFAIK, 24 years later a 'cp /dev/rsd0b' still has a 50-50 chance of
failure. :)

James Dow Allen
 
B

Ben Bacarisse

Keith Thompson said:
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.

Yes, but it would fail in some other cases. In particular, it answers
the original question: an N-element char array must have size N for this
idiom to work.
 
P

Philip Lantz

James said:
This discussion reminds me of a true story from 24 years ago that might
interest or amuse. I wanted to look at the label on a disk so adopted a
"minimum keystroke" solution:
cp /dev/rsd0b copy_of_label
^C
To my surprise, the data in 'copy' was scrambled, i.e. odd and even
shorts were swapped.

There were four bugs or bug-like features interacting:
(1) The SCSI controller hardware operated properly only on 4-byte
aligned buffer addresses.
(2) The SCSI driver neglected to cheeck for that alignment.
(3) The program cp.c (which used mmap() for most reads) did reads from
special devices with simply
char buffer[512];
read(infd, buffer, 512);
(4) The cc compiler, faced with a declaration like "char buffer[512]",
saw fit to guarantee 2-byte alignment, but not 4-byte alignment.

I thought this strange episode had instructive features. The clearest
bug might be (1), but it was more-or-less unfixable. Why make a
complicated hardware change to accomodate a yokel who reads disk-labels
with 'cp'? (2) was a blatant stupidity, but correcting it wouldn't
completely solve the problem: The yokel would still get IO_error,
though that is much better than scrambled data or kernel panic.

Neither (3) nor (4) were considered "bugs" -- both the compiler and cp.c
were doing that which they were allowed to do by specs. At the same
time, it seemed both simple and appropriate to fix the problem by
amending cp.c and/or the compiler.

A fix for cp.c would take 2 minutes of coding labor (no, I wouldn't
really fix it as above) and several hours in the Bug Tracking and
Approval program. cp's maintainer was uninterested: his program "did
nothing wrong."

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. The read system call has
never had any alignment restriction on the buffer. The driver was at
fault, as Scott pointed out. If it is supposed to be a general purpose
driver, it needs to work with any provided buffer. (If the driver is
only intended to work with specific clients, such as a file-system
driver, it might be reasonable for it to return I/O error in this case,
making it the user's fault for using the driver inappropriately.)

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

Philip
 

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,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top