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

Discussion in 'C Programming' started by Francois Grieu, Feb 22, 2012.

  1. 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;
    }
    Francois Grieu, Feb 22, 2012
    #1
    1. Advertising

  2. Francois Grieu

    Stefan Ram Guest

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

    Francois Grieu <> writes:
    >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).
    Stefan Ram, Feb 22, 2012
    #2
    1. Advertising

  3. Francois Grieu <> writes:

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

    --
    Ben.
    Ben Bacarisse, Feb 22, 2012
    #3
  4. Francois Grieu

    Stefan Ram Guest

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

    Ben Bacarisse <> writes:
    >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)«.
    Stefan Ram, Feb 22, 2012
    #4
  5. On 22-Feb-12 08:06, Ben Bacarisse wrote:
    > Francois Grieu <> writes:
    >> 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

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
    Stephen Sprunk, Feb 22, 2012
    #5
  6. On 22/02/2012 15:06, Ben Bacarisse wrote:
    > Francois Grieu <> writes:
    >
    >> 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?
    Francois Grieu, Feb 22, 2012
    #6
  7. Re: what's the size of type char [3] ?

    -berlin.de (Stefan Ram) writes:

    > Ben Bacarisse <> writes:
    >>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)«.


    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.

    --
    Ben.
    Ben Bacarisse, Feb 22, 2012
    #7
  8. Francois Grieu <> writes:

    > On 22/02/2012 15:06, Ben Bacarisse wrote:
    >> Francois Grieu <> writes:
    >>
    >>> 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.

    --
    Ben.
    Ben Bacarisse, Feb 22, 2012
    #8
  9. Francois Grieu

    jacob navia Guest

    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.
    jacob navia, Feb 22, 2012
    #9
  10. Francois Grieu

    BartC Guest

    "jacob navia" <> wrote in message
    news:ji3ejc$oa9$...
    > 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...)

    --
    Bartc
    BartC, Feb 22, 2012
    #10
  11. On Wed, 22 Feb 2012 14:06:55 +0000, Ben Bacarisse
    <> wrote:

    >Francois Grieu <> writes:
    >
    >> 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?

    --
    Remove del for email
    Barry Schwarz, Feb 22, 2012
    #11
  12. Francois Grieu

    jacob navia Guest

    Le 22/02/12 15:06, Ben Bacarisse a écrit :
    > Francois Grieu<> writes:
    >
    >> 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!
    jacob navia, Feb 22, 2012
    #12
  13. Barry Schwarz <> writes:

    > On Wed, 22 Feb 2012 14:06:55 +0000, Ben Bacarisse
    > <> wrote:
    >
    >>Francois Grieu <> writes:
    >>
    >>> 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.

    --
    Ben.
    Ben Bacarisse, Feb 22, 2012
    #13
  14. Francois Grieu

    Stefan Ram Guest

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

    Ben Bacarisse <> writes:
    >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.
    Stefan Ram, Feb 23, 2012
    #14
  15. Re: what's the size of type char [3] ?

    -berlin.de (Stefan Ram) writes:

    > Ben Bacarisse <> writes:
    >>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.


    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.

    --
    Ben.
    Ben Bacarisse, Feb 23, 2012
    #15
  16. Re: what's the size of type char [3] ?

    Ben Bacarisse <> writes:
    > -berlin.de (Stefan Ram) writes:
    >> Ben Bacarisse <> writes:
    >>>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.

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

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 23, 2012
    #16
  17. Re: what's the size of type char [3] ?

    On Feb 23, 7:03 am, Keith Thompson <> wrote:
    > Ben Bacarisse <> writes:
    > > -berlin.de (Stefan Ram) writes:
    > >> Ben Bacarisse <> writes:
    > >>>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.

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


    but in the case of a char array...
    Nick Keighley, Feb 23, 2012
    #17
  18. 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
    James Dow Allen, Feb 23, 2012
    #18
  19. Re: what's the size of type char [3] ?

    Keith Thompson <> writes:

    > Ben Bacarisse <> writes:
    >> -berlin.de (Stefan Ram) writes:
    >>> Ben Bacarisse <> writes:
    >>>>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.

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


    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.

    --
    Ben.
    Ben Bacarisse, Feb 23, 2012
    #19
  20. Francois Grieu

    Philip Lantz Guest

    James Dow Allen wrote:
    >
    > 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
    Philip Lantz, Feb 24, 2012
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex Vinokur
    Replies:
    7
    Views:
    436
    Jerry Coffin
    Sep 21, 2003
  2. Replies:
    3
    Views:
    383
    John Roth
    Jul 29, 2005
  3. lovecreatesbeauty
    Replies:
    1
    Views:
    1,045
    Ian Collins
    May 9, 2006
  4. .rhavin grobert

    vector: Foo[5] == ((foo*)Foo) + 5 ?

    .rhavin grobert, Sep 23, 2008, in forum: C++
    Replies:
    4
    Views:
    390
    JaredGrubb
    Sep 24, 2008
  5. Replies:
    4
    Views:
    143
    Thomas 'PointedEars' Lahn
    Dec 23, 2007
Loading...

Share This Page