Returning a struct from a function - strange behavior

Discussion in 'C Programming' started by DiAvOl, Oct 7, 2008.

  1. DiAvOl

    DiAvOl Guest

    Hello everyone,

    Please take a look at the following code:

    #include <stdio.h>

    typedef struct person {
    char name[40];
    int age;
    } Person;

    static Person make_person(void);

    int main(void) {
    printf("%s\n", make_person().name);

    return 0;
    }

    static Person make_person(void) {
    static Person p = { "alexander", 18 };

    return p;
    }

    The above small program when compiled without the -std=c99 option
    (using gcc 4.2.3) gives me a warning:
    "warning: format ‘%s’ expects type ‘char *’, but argument 2 has type
    ‘char[40]’"
    and also fails with a segmentation fault when executed.

    If I replace the line printf("%s\n", make_person().name); with
    printf("%s\n", &make_person().name[0]); everything works as expected.

    Why does this happen? Isn't make_person().name a pointer to the
    array's first element?

    Someone replied to this (in the gcc bugzilla), I am quoting the
    answer:

    "make_person().name is a non-lvalue array, so it only decays to a
    pointer
    for C99, not for C90. If you use -std=c99/-std=gnu99 then the
    program
    works.

    The program does not, however, have defined behavior for C99, only
    for
    C1x. In C99 the lifetime of the array ends at the next sequence
    point,
    before the call to printf. In C1x it instead ends at the end of the
    evaluation of the containing full expression, which is the call to
    printf.

    I do not believe any changes to GCC are needed to implement this
    particular C1x requirement, since GCC discards information about
    variables
    lifetimes smaller than a function for gimplification and tree
    optimizations that may change those lifetimes, so it will in practice
    treat the lifetime as being anywhere it cannot show the temporary not
    to
    be live."

    I can't understand why make_person().name is not an lvalue array and
    only decays to a pointer for C99. Can someone please explain this?

    Also what does this guy mean with the line "In C99 the lifetime of the
    array ends at the next sequence point,
    before the call to printf"? A function call is a sequence point?

    I am having a hard time understanding this one, any help appreciated
    Thanks for your time

    PS. I tried the lcc compiler which compiled the code without warnings/
    errors
     
    DiAvOl, Oct 7, 2008
    #1
    1. Advertising

  2. DiAvOl

    DiAvOl Guest

    One more question:

    Is there any (Person) variable created in main to hold the
    make_person() return value?
    If this is the case, does all the values from the returned struct be
    copied to the variable mentioned above?
     
    DiAvOl, Oct 7, 2008
    #2
    1. Advertising

  3. DiAvOl <> wrote:
    > Hello everyone,
    >
    > Please take a look at the following code:
    >
    > #include <stdio.h>
    >
    > typedef struct person {
    >   char name[40];
    >   int age;
    >
    > } Person;
    >
    > static Person make_person(void);
    >
    > int main(void) {
    >   printf("%s\n", make_person().name);
    >   return 0;
    > }
    >
    > static Person make_person(void) {
    >   static Person p = { "alexander", 18 };
    >   return p;
    > }
    >
    > The above small program when compiled without the
    > -std=c99 option (using gcc 4.2.3) gives me a warning:
    > "warning: format ‘%s’ expects type ‘char *’, but
    > argument 2 has type ‘char[40]’"
    > and also fails with a segmentation fault when executed.


    That's a bug in gcc 4.2.3 then. [The same segfault
    happens with -ansi.]

    > If I replace the line printf("%s\n", make_person().name);
    > with printf("%s\n", &make_person().name[0]); everything
    > works as expected.
    >
    > Why does this happen?


    Because there's a bug in gcc 4.2.3.

    > Isn't make_person().name a pointer to the array's first
    > element?


    Since it's not the operand to an unary & or sizeof operator,
    yes.

    > Someone replied to this (in the gcc bugzilla), I am
    > quoting the answer:
    >
    > "make_person().name is a non-lvalue array, so it only
    > decays to a pointer for C99, not for C90.


    Ask them for chapter and verse. And ask them why
    printf("%s\n", "hello") isn't ill formed for the same
    reason.

    C89 (draft):

    "An lvalue is an expression (with an object
    type or an incomplete type other than void) that
    designates an object."

    "Except when it is the operand of the sizeof
    operator or the unary & operator, or is a character string
    literal used to initialize an array of character type, or
    is a wide string literal used to initialize an array with
    element type compatible with wchar_t, an lvalue that has
    type ``array of type '' is converted to an expression that
    has type ``pointer to type '' that points to the initial
    member of the array object and is not an lvalue.

    C99:

    6.3.2.1p1 "An lvalue is an expression (with an object
    type or an incomplete type other than void) that designates
    an object."

    6.3.2.1p3 "Except when it is the operand of the sizeof
    operator or the unary & operator, or is a string literal
    used to initialize an array, an expression that has type
    ‘‘array of type’’ is converted to an expression with type
    ‘‘pointer to type’’ that points to the initial element of
    the array object and is not an lvalue."

    An lvalue is only explicitly required in C90. But in either
    case, make_person().name is an lvalue.

    --
    Peter
     
    Peter Nilsson, Oct 7, 2008
    #3
  4. On Mon, 6 Oct 2008 18:34:34 -0700 (PDT), DiAvOl <>
    wrote:

    >One more question:
    >
    >Is there any (Person) variable created in main to hold the
    >make_person() return value?


    Officially, it is an implementation detail about which the standard
    imposes no requirement.

    Practically, if you had ignored the return value, the answer might be
    no. Since you use the return value, the answer is almost definitely
    yes. But the variable in question is one of those temporary
    constructs known only to the compiler. There is no way for you to
    access it. Since it has no name, one could argue that it is not a
    variable or object.

    >If this is the case, does all the values from the returned struct be
    >copied to the variable mentioned above?


    Possibly. Maybe even probably. Under the "how would you tell the
    difference" concept, the compiler could probably determine you only
    need the member name and not copy the member age.

    By the way, since the structure is returned by value, there is no need
    for it to be static in your function.

    --
    Remove del for email
     
    Barry Schwarz, Oct 7, 2008
    #4
  5. DiAvOl

    Guest

    On Oct 7, 9:23 am, DiAvOl <> wrote:
    > int main(void) {
    >   printf("%s\n", make_person().name);
    >
    >   return 0;
    >
    > }
    >


    why don't you code it in this way.

    int main(void){
    Person p;

    p = make_person();
    printf("%s\n", p.name);

    /*printf("%s\n", make_person().name);*/
    return 0;
    }
     
    , Oct 7, 2008
    #5
  6. Peter Nilsson <> writes:
    > DiAvOl <> wrote:
    >> Hello everyone,
    >>
    >> Please take a look at the following code:
    >>
    >> #include <stdio.h>
    >>
    >> typedef struct person {
    >>   char name[40];
    >>   int age;
    >>
    >> } Person;
    >>
    >> static Person make_person(void);
    >>
    >> int main(void) {
    >>   printf("%s\n", make_person().name);
    >>   return 0;
    >> }
    >>
    >> static Person make_person(void) {
    >>   static Person p = { "alexander", 18 };
    >>   return p;
    >> }
    >>
    >> The above small program when compiled without the
    >> -std=c99 option (using gcc 4.2.3) gives me a warning:
    >> "warning: format ‘%s’ expects type ‘char *’, but
    >> argument 2 has type ‘char[40]’"
    >> and also fails with a segmentation fault when executed.

    >
    > That's a bug in gcc 4.2.3 then. [The same segfault
    > happens with -ansi.]


    No, I don't think it's a bug.

    [...]
    >> Someone replied to this (in the gcc bugzilla), I am
    >> quoting the answer:
    >>
    >> "make_person().name is a non-lvalue array, so it only
    >> decays to a pointer for C99, not for C90.

    >
    > Ask them for chapter and verse. And ask them why
    > printf("%s\n", "hello") isn't ill formed for the same
    > reason.


    Because "hello" refers to an object of type char[6]; see the
    definition of a string literal. There's no object of type Person.

    A function returns a value. There isn't necessarily an object
    associated with that value. Given:

    int func(void) { return 42; }

    func returns the value 42; there's no object whose address you could
    take, such that dereferencing that address would give you the value
    42.

    [...]

    > An lvalue is only explicitly required in C90. But in either
    > case, make_person().name is an lvalue.


    I don't believe it is. make_person() yields a value of type Person.
    make_person().age yields a value of type int. make_person().name
    reveals an anomaly in the C type system; it should be a value of type
    char[40], which should decay to a pointer to the first element of the
    corresponding array object, but there is no array object, just a
    value.

    And this specific case is why the following was added in n1336, the
    first C201X draft (6.2.4p7):

    A non-lvalue expression with structure or union type, where the
    structure or union contains a member with array type (including,
    recursively, members of all contained structures and unions)
    refers to an object with automatic storage duration and _temporary
    lifetime_ 29). Its lifetime begins when the expression is
    evaluated and its initial value is the value of the
    expression. Its lifetime ends when the evaluation of the
    containing full expression or full declarator ends. Any attempt to
    modify an object with temporary lifetime results in undefined
    behavior.

    Footnote 29 says:

    The address of such an object is taken implicitly when an array
    member is accessed.

    This new rule means that there is an object of type Person, causing
    make_person.name() to be an lvalue. In C90 or C99, it's not an
    lvalue.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Oct 7, 2008
    #6
  7. "" <> writes:
    > On Oct 7, 9:23 am, DiAvOl <> wrote:
    >> int main(void) {
    >>   printf("%s\n", make_person().name);
    >>
    >>   return 0;
    >>
    >> }
    >>

    >
    > why don't you code it in this way.
    >
    > int main(void){
    > Person p;
    >
    > p = make_person();
    > printf("%s\n", p.name);
    >
    > /*printf("%s\n", make_person().name);*/
    > return 0;
    > }


    Because that doesn't illustrate the point.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Oct 7, 2008
    #7
  8. DiAvOl

    jacob navia Guest

    DiAvOl wrote:
    > Hello everyone,
    >
    > Please take a look at the following code:
    >
    > #include <stdio.h>
    >
    > typedef struct person {
    > char name[40];
    > int age;
    > } Person;
    >
    > static Person make_person(void);
    >
    > int main(void) {
    > printf("%s\n", make_person().name);
    >
    > return 0;
    > }
    >
    > static Person make_person(void) {
    > static Person p = { "alexander", 18 };
    >
    > return p;
    > }
    >
    > The above small program when compiled without the -std=c99 option
    > (using gcc 4.2.3) gives me a warning:
    > "warning: format ‘%s’ expects type ‘char *’, but argument 2 has type
    > ‘char[40]’"
    > and also fails with a segmentation fault when executed.
    >
    > If I replace the line printf("%s\n", make_person().name); with
    > printf("%s\n", &make_person().name[0]); everything works as expected.
    >
    > Why does this happen? Isn't make_person().name a pointer to the
    > array's first element?
    >
    > Someone replied to this (in the gcc bugzilla), I am quoting the
    > answer:
    >
    > "make_person().name is a non-lvalue array, so it only decays to a
    > pointer
    > for C99, not for C90. If you use -std=c99/-std=gnu99 then the
    > program
    > works.
    >
    > The program does not, however, have defined behavior for C99, only
    > for
    > C1x. In C99 the lifetime of the array ends at the next sequence
    > point,
    > before the call to printf. In C1x it instead ends at the end of the
    > evaluation of the containing full expression, which is the call to
    > printf.
    >
    > I do not believe any changes to GCC are needed to implement this
    > particular C1x requirement, since GCC discards information about
    > variables
    > lifetimes smaller than a function for gimplification and tree
    > optimizations that may change those lifetimes, so it will in practice
    > treat the lifetime as being anywhere it cannot show the temporary not
    > to
    > be live."
    >
    > I can't understand why make_person().name is not an lvalue array and
    > only decays to a pointer for C99. Can someone please explain this?
    >
    > Also what does this guy mean with the line "In C99 the lifetime of the
    > array ends at the next sequence point,
    > before the call to printf"? A function call is a sequence point?
    >
    > I am having a hard time understanding this one, any help appreciated
    > Thanks for your time
    >
    > PS. I tried the lcc compiler which compiled the code without warnings/
    > errors



    Yes, lcc-win compiles and executes correctly your code. As does
    MSVC, that correctly executes it.


    --
    jacob navia
    jacob at jacob point remcomp point fr
    logiciels/informatique
    http://www.cs.virginia.edu/~lcc-win32
     
    jacob navia, Oct 7, 2008
    #8
  9. DiAvOl

    Guest

    On Oct 7, 2:57 pm, Keith Thompson <> wrote:
    > "" <> writes:
    > > On Oct 7, 9:23 am, DiAvOl <> wrote:
    > >> int main(void) {
    > >>   printf("%s\n", make_person().name);

    >
    > >>   return 0;

    >
    > >> }

    >
    > > why don't you code it in this way.

    >
    > > int main(void){
    > >         Person p;

    >
    > >         p = make_person();
    > >         printf("%s\n", p.name);

    >
    > >         /*printf("%s\n", make_person().name);*/
    > >         return 0;
    > > }

    >
    > Because that doesn't illustrate the point.
    >


    The op's code is wrong and my revision is right, isn't it?
     
    , Oct 7, 2008
    #9
  10. On 7 Oct, 09:28, ""
    <> wrote:
    > On Oct 7, 2:57 pm, Keith Thompson <> wrote:
    >
    >
    >
    >
    >
    > > "" <> writes:
    > > > On Oct 7, 9:23 am, DiAvOl <> wrote:
    > > >> int main(void) {
    > > >>   printf("%s\n", make_person().name);

    >
    > > >>   return 0;

    >
    > > >> }

    >
    > > > why don't you code it in this way.

    >
    > > > int main(void){
    > > >         Person p;

    >
    > > >         p = make_person();
    > > >         printf("%s\n", p.name);

    >
    > > >         /*printf("%s\n", make_person().name);*/
    > > >         return 0;
    > > > }

    >
    > > Because that doesn't illustrate the point.

    >
    > The op's code is wrong and my revision is right, isn't it


    the point is that it is not obvious why the OPs code is
    wrong. It surprised me.

    --
    Nick Keighley
     
    Nick Keighley, Oct 7, 2008
    #10
  11. Nick Keighley wrote:
    > On 7 Oct, 09:28, ""
    > <> wrote:
    >> On Oct 7, 2:57 pm, Keith Thompson <> wrote:
    >>
    >>
    >>
    >>
    >>
    >>> "" <> writes:
    >>>> On Oct 7, 9:23 am, DiAvOl <> wrote:
    >>>>> int main(void) {
    >>>>> printf("%s\n", make_person().name);
    >>>>> return 0;
    >>>>> }
    >>>> why don't you code it in this way.
    >>>> int main(void){
    >>>> Person p;
    >>>> p = make_person();
    >>>> printf("%s\n", p.name);
    >>>> /*printf("%s\n", make_person().name);*/
    >>>> return 0;
    >>>> }
    >>> Because that doesn't illustrate the point.

    >> The op's code is wrong and my revision is right, isn't it

    >
    > the point is that it is not obvious why the OPs code is
    > wrong. It surprised me.


    It still surprises me, since _my_ copy of gcc 4.2.3 with -W -Wall
    0std=c99 -pedantic neither reports the diagnostic nor eegfaults.
     
    Martin Ambuhl, Oct 7, 2008
    #11
  12. DiAvOl

    DiAvOl Guest

    On Oct 7, 9:50 am, Keith Thompson <> wrote:
    [...]
    > > An lvalue is only explicitly required in C90. But in either
    > > case, make_person().name is an lvalue.

    >
    > I don't believe it is.  make_person() yields a value of type Person.
    > make_person().age yields a value of type int.  make_person().name
    > reveals an anomaly in the C type system; it should be a value of type
    > char[40], which should decay to a pointer to the first element of the
    > corresponding array object, but there is no array object, just a
    > value.


    My question then is if there is no array object why does the
    &make_person().name[0] works?

    Thanks for your answers
     
    DiAvOl, Oct 7, 2008
    #12
  13. On 7 Oct, 10:01, Martin Ambuhl <> wrote:
    > Nick Keighley wrote:
    > > On 7 Oct, 09:28, ""
    > > <> wrote:
    > >> On Oct 7, 2:57 pm, Keith Thompson <> wrote:

    >
    > >>> "" <> writes:
    > >>>> On Oct 7, 9:23 am, DiAvOl <> wrote:
    > >>>>> int main(void) {
    > >>>>>   printf("%s\n", make_person().name);
    > >>>>>   return 0;
    > >>>>> }
    > >>>> why don't you code it in this way.
    > >>>> int main(void){
    > >>>>         Person p;
    > >>>>         p = make_person();
    > >>>>         printf("%s\n", p.name);
    > >>>>         /*printf("%s\n", make_person().name);*/
    > >>>>         return 0;
    > >>>> }
    > >>> Because that doesn't illustrate the point.
    > >> The op's code is wrong and my revision is right, isn't it

    >
    > > the point is that it is not obvious why the OPs code is
    > > wrong. It surprised me.

    >
    > It still surprises me, since _my_ copy of gcc 4.2.3 with -W -Wall
    > 0std=c99 -pedantic neither reports the diagnostic nor eegfaults


    so is the program incorrect? Or did a particular version
    of gcc have a bug? If the program is exhibiting UB then
    translating it and running it to produce the "expected"
    behaviour is perfectly ok!

    --
    Nick Keighley
     
    Nick Keighley, Oct 7, 2008
    #13
  14. On Tue, 07 Oct 2008 05:01:25 -0400,
    Martin Ambuhl <> wrote:
    >
    > It still surprises me, since _my_ copy of gcc 4.2.3 with -W -Wall
    > 0std=c99 -pedantic neither reports the diagnostic nor eegfaults.


    The OP wrote:

    > The above small program when compiled without the -std=c99 option


    and later

    > Someone replied to this (in the gcc bugzilla), I am quoting the
    > answer:
    >
    > "make_person().name is a non-lvalue array, so it only decays to a
    > pointer for C99, not for C90. If you use -std=c99/-std=gnu99 then
    > the program works.


    The problem occurs only when compiling the program as a C90 program with
    gcc. When compiling it as a C99 program it's fine. Try it with -ansi, or
    -std=c89.

    Martien
    --
    |
    Martien Verbruggen | In the fight between you and the world, back
    | the world - Franz Kafka
    |
     
    Martien Verbruggen, Oct 7, 2008
    #14
  15. DiAvOl

    Guest

    On Oct 7, 9:50 am, Keith Thompson <> wrote:
    > Peter Nilsson <> writes:
    > > DiAvOl <> wrote:
    > >> Hello everyone,

    >
    > >> Please take a look at the following code:

    >
    > >> #include <stdio.h>

    >
    > >> typedef struct person {
    > >> char name[40];
    > >> int age;

    >
    > >> } Person;

    >
    > >> static Person make_person(void);

    >
    > >> int main(void) {
    > >> printf("%s\n", make_person().name);
    > >> return 0;
    > >> }

    >
    > >> static Person make_person(void) {
    > >> static Person p = { "alexander", 18 };
    > >> return p;
    > >> }

    >
    > >> The above small program when compiled without the
    > >> -std=c99 option (using gcc 4.2.3) gives me a warning:
    > >> "warning: format ‘%s’ expects type ‘char *’, but
    > >> argument 2 has type ‘char[40]’"
    > >> and also fails with a segmentation fault when executed.


    Assuming you have 32bit pointers, the contents of the string are
    passed where void * is expected.
    It's not a bug in gcc.

    > I don't believe it is. make_person() yields a value of type Person.
    > make_person().age yields a value of type int. make_person().name
    > reveals an anomaly in the C type system; it should be a value of type
    > char[40], which should decay to a pointer to the first element of the
    > corresponding array object, but there is no array object, just a
    > value.


    I don't think it's an anomaly.
    It's the reason this works as I understand it.

    fwrite(&"hello", 1, sizeof "hello", stdout);

    &"hello" has type char (*)[6].
    When the pointer value is dereferenced as (char *), the correct values
    are written; 'h', 'e', etc.
    This wouldn't be the case with

    char *p = "hello";
    fwrite(&p, 1, sizeof "hello", stdout);

    For example.

    If I'm correct, the value of an array is its contents, at least that's
    what appears to be the case in C89, or in GCC's implementation of C89.

    Here's a demonstration program: (btw, yes I know I invoke undefined
    behavior)

    /* assumes 4 byte long */
    #include <stdio.h>
    struct foo { char test[40]; };
    struct foo f(void) { struct foo bar; strcpy(bar.test, "1234"); return
    bar; }

    int main(void) {

    printf("%ld == ", *(long *)"1234");
    printf("%ld\n", f().test);

    return 0;
    }
     
    , Oct 7, 2008
    #15
  16. DiAvOl

    Guest

    On Oct 7, 4:53 pm, wrote:
    <snip>
    > When the pointer value is dereferenced as (char *), the correct values


    Or (unsigned char *), but that wasn't the point...
     
    , Oct 7, 2008
    #16
  17. On 7 Oct, 14:53, wrote:
    > On Oct 7, 9:50 am, Keith Thompson <> wrote:
    > > Peter Nilsson <> writes:
    > > > DiAvOl <> wrote:


    > > >> Please take a look at the following code:

    >
    > > >> #include <stdio.h>

    >
    > > >> typedef struct person {
    > > >> char name[40];
    > > >> int age;

    >
    > > >> } Person;

    >
    > > >> static Person make_person(void);

    >
    > > >> int main(void) {
    > > >> printf("%s\n", make_person().name);
    > > >> return 0;
    > > >> }

    >
    > > >> static Person make_person(void) {
    > > >> static Person p = { "alexander", 18 };
    > > >> return p;
    > > >> }

    >
    > > >> The above small program when compiled without the
    > > >> -std=c99 option (using gcc 4.2.3) gives me a warning:
    > > >> "warning: format ‘%s’ expects type ‘char *’, but
    > > >> argument 2 has type ‘char[40]’"
    > > >> and also fails with a segmentation fault when executed.

    >
    > Assuming you have 32bit pointers, the contents of the string are
    > passed where void * is expected.


    what? Why is thre a void* expected?


    > It's not a bug in gcc.
    >
    > > I don't believe it is. make_person() yields a value of type Person.
    > > make_person().age yields a value of type int. make_person().name
    > > reveals an anomaly in the C type system; it should be a value of type
    > > char[40], which should decay to a pointer to the first element of the
    > > corresponding array object, but there is no array object, just a
    > > value.

    >
    > I don't think it's an anomaly.
    > It's the reason this works as I understand it.
    >
    > fwrite(&"hello", 1, sizeof "hello", stdout);
    >
    > &"hello" has type char (*)[6].
    > When the pointer value is dereferenced as (char *), the correct values
    > are written; 'h', 'e', etc.
    > This wouldn't be the case with
    >
    > char *p = "hello";
    > fwrite(&p, 1, sizeof "hello", stdout);


    I think you're adding confusion. The original code didn't have
    array pointers in it. It had arrays.
    <snip>

    --
    Nick Keighley
     
    Nick Keighley, Oct 7, 2008
    #17
  18. DiAvOl

    Guest

    On Oct 7, 5:29 pm, Nick Keighley <>
    wrote:
    > On 7 Oct, 14:53, wrote:
    >
    >
    >
    > > On Oct 7, 9:50 am, Keith Thompson <> wrote:
    > > > Peter Nilsson <> writes:
    > > > > DiAvOl <> wrote:
    > > > >> Please take a look at the following code:

    >
    > > > >> #include <stdio.h>

    >
    > > > >> typedef struct person {
    > > > >> char name[40];
    > > > >> int age;

    >
    > > > >> } Person;

    >
    > > > >> static Person make_person(void);

    >
    > > > >> int main(void) {
    > > > >> printf("%s\n", make_person().name);
    > > > >> return 0;
    > > > >> }

    >
    > > > >> static Person make_person(void) {
    > > > >> static Person p = { "alexander", 18 };
    > > > >> return p;
    > > > >> }

    >
    > > > >> The above small program when compiled without the
    > > > >> -std=c99 option (using gcc 4.2.3) gives me a warning:
    > > > >> "warning: format ‘%s’ expects type ‘char *’, but
    > > > >> argument 2 has type ‘char[40]’"
    > > > >> and also fails with a segmentation fault when executed.

    >
    > > Assuming you have 32bit pointers, the contents of the string are
    > > passed where void * is expected.

    >
    > what? Why is thre a void* expected?


    Sorry I was talking about pointers then I thought the conversion
    specifier was p :p
    It's s, and char * was expected.

    >
    >
    > > It's not a bug in gcc.

    >
    > > > I don't believe it is. make_person() yields a value of type Person.
    > > > make_person().age yields a value of type int. make_person().name
    > > > reveals an anomaly in the C type system; it should be a value of type
    > > > char[40], which should decay to a pointer to the first element of the
    > > > corresponding array object, but there is no array object, just a
    > > > value.

    >
    > > I don't think it's an anomaly.
    > > It's the reason this works as I understand it.

    >
    > > fwrite(&"hello", 1, sizeof "hello", stdout);

    >
    > > &"hello" has type char (*)[6].
    > > When the pointer value is dereferenced as (char *), the correct values
    > > are written; 'h', 'e', etc.
    > > This wouldn't be the case with

    >
    > > char *p = "hello";
    > > fwrite(&p, 1, sizeof "hello", stdout);

    >
    > I think you're adding confusion. The original code didn't have
    > array pointers in it. It had arrays.


    I was adding to Keiths post, which mentioned array values.
     
    , Oct 7, 2008
    #18
  19. writes:
    > On Oct 7, 9:50 am, Keith Thompson <> wrote:
    >> Peter Nilsson <> writes:
    >> > DiAvOl <> wrote:
    >> >> Hello everyone,

    >>
    >> >> Please take a look at the following code:

    >>
    >> >> #include <stdio.h>

    >>
    >> >> typedef struct person {
    >> >> char name[40];
    >> >> int age;

    >>
    >> >> } Person;

    >>
    >> >> static Person make_person(void);

    >>
    >> >> int main(void) {
    >> >> printf("%s\n", make_person().name);
    >> >> return 0;
    >> >> }

    >>
    >> >> static Person make_person(void) {
    >> >> static Person p = { "alexander", 18 };
    >> >> return p;
    >> >> }

    >>
    >> >> The above small program when compiled without the
    >> >> -std=c99 option (using gcc 4.2.3) gives me a warning:
    >> >> "warning: format ‘%s’ expects type ‘char *’, but
    >> >> argument 2 has type ‘char[40]’"
    >> >> and also fails with a segmentation fault when executed.

    >
    > Assuming you have 32bit pointers, the contents of the string are
    > passed where void * is expected.
    > It's not a bug in gcc.


    That does appear to be what it's doing (with the version I used,
    *without* the "-std=c99" option), but I don't see how you conclude
    that it's not a bug.

    I *think* that the behavior is undefined in both C90 and C99 (but
    becomes well defined in C201X).

    BTW, in a followup you corrected "void *" to "unsigned char *"; in
    fact, printf's "%s" expects "char*".

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Oct 7, 2008
    #19
  20. DiAvOl

    Guest

    On Oct 7, 6:31 pm, Keith Thompson <> wrote:
    > writes:

    <snip>
    > > Assuming you have 32bit pointers, the contents of the string are
    > > passed where void * is expected.
    > > It's not a bug in gcc.

    >
    > That does appear to be what it's doing (with the version I used,
    > *without* the "-std=c99" option), but I don't see how you conclude
    > that it's not a bug.
    >
    > I *think* that the behavior is undefined in both C90 and C99 (but
    > becomes well defined in C201X).


    I don't think so, but it may be true. I'm going to do some reading in
    the C99 standard and perhaps find out.

    > BTW, in a followup you corrected "void *" to "unsigned char *"; in
    > fact, printf's "%s" expects "char*".


    I corrected a different void *. I was talking about fwrite accessing
    its void * parameter as (char *).
     
    , Oct 7, 2008
    #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. Chris Fogelklou
    Replies:
    36
    Views:
    1,441
    Chris Fogelklou
    Apr 20, 2004
  2. Ole
    Replies:
    4
    Views:
    623
    Michael Wojcik
    Oct 26, 2004
  3. Army1987
    Replies:
    19
    Views:
    501
    Richard Tobin
    May 19, 2007
  4. Replies:
    12
    Views:
    570
    Richard Herring
    May 20, 2008
  5. Shao Miller

    Function Returning Anonymous Struct

    Shao Miller, Aug 6, 2010, in forum: C Programming
    Replies:
    2
    Views:
    1,193
    Shao Miller
    Aug 7, 2010
Loading...

Share This Page