By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
464,447 Members | 1,051 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 464,447 IT Pros & Developers. It's quick & easy.

Returning a struct from a function - strange behavior

P: n/a
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
Oct 7 '08 #1
Share this Question
Share on Google+
160 Replies

P: n/a
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?
Oct 7 '08 #2

P: n/a
DiAvOl <dia...@freemail.grwrote:
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
Oct 7 '08 #3

P: n/a
On Mon, 6 Oct 2008 18:34:34 -0700 (PDT), DiAvOl <di****@freemail.gr>
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
Oct 7 '08 #4

P: n/a
On Oct 7, 9:23*am, DiAvOl <dia...@freemail.grwrote:
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 '08 #5

P: n/a
Peter Nilsson <ai***@acay.com.auwrites:
DiAvOl <dia...@freemail.grwrote:
>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) ks***@mib.org <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"
Oct 7 '08 #6

P: n/a
"lo***************@gmail.com" <lo***************@gmail.comwrites:
On Oct 7, 9:23*am, DiAvOl <dia...@freemail.grwrote:
>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) ks***@mib.org <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"
Oct 7 '08 #7

P: n/a
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
Oct 7 '08 #8

P: n/a
On Oct 7, 2:57*pm, Keith Thompson <ks...@mib.orgwrote:
"lovecreatesbea...@gmail.com" <lovecreatesbea...@gmail.comwrites:
On Oct 7, 9:23*am, DiAvOl <dia...@freemail.grwrote:
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 '08 #9

P: n/a
On 7 Oct, 09:28, "lovecreatesbea...@gmail.com"
<lovecreatesbea...@gmail.comwrote:
On Oct 7, 2:57*pm, Keith Thompson <ks...@mib.orgwrote:


"lovecreatesbea...@gmail.com" <lovecreatesbea...@gmail.comwrites:
On Oct 7, 9:23*am, DiAvOl <dia...@freemail.grwrote:
>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

Oct 7 '08 #10

P: n/a
Nick Keighley wrote:
On 7 Oct, 09:28, "lovecreatesbea...@gmail.com"
<lovecreatesbea...@gmail.comwrote:
>On Oct 7, 2:57 pm, Keith Thompson <ks...@mib.orgwrote:


>>"lovecreatesbea...@gmail.com" <lovecreatesbea...@gmail.comwrites:
On Oct 7, 9:23 am, DiAvOl <dia...@freemail.grwrote:
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.
Oct 7 '08 #11

P: n/a
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgwrote:
[...]
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

Oct 7 '08 #12

P: n/a
On 7 Oct, 10:01, Martin Ambuhl <mamb...@earthlink.netwrote:
Nick Keighley wrote:
On 7 Oct, 09:28, "lovecreatesbea...@gmail.com"
<lovecreatesbea...@gmail.comwrote:
On Oct 7, 2:57 pm, Keith Thompson <ks...@mib.orgwrote:
>"lovecreatesbea...@gmail.com" <lovecreatesbea...@gmail.comwrites:
On Oct 7, 9:23 am, DiAvOl <dia...@freemail.grwrote:
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
Oct 7 '08 #13

P: n/a
On Tue, 07 Oct 2008 05:01:25 -0400,
Martin Ambuhl <ma*****@earthlink.netwrote:
>
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
|
Oct 7 '08 #14

P: n/a
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgwrote:
Peter Nilsson <ai...@acay.com.auwrites:
DiAvOl <dia...@freemail.grwrote:
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 '08 #15

P: n/a
On Oct 7, 4:53 pm, vipps...@gmail.com wrote:
<snip>
When the pointer value is dereferenced as (char *), the correct values
Or (unsigned char *), but that wasn't the point...
Oct 7 '08 #16

P: n/a
On 7 Oct, 14:53, vipps...@gmail.com wrote:
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgwrote:
Peter Nilsson <ai...@acay.com.auwrites:
DiAvOl <dia...@freemail.grwrote:
>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

Oct 7 '08 #17

P: n/a
On Oct 7, 5:29 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
wrote:
On 7 Oct, 14:53, vipps...@gmail.com wrote:
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgwrote:
Peter Nilsson <ai...@acay.com.auwrites:
DiAvOl <dia...@freemail.grwrote:
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 '08 #18

P: n/a
vi******@gmail.com writes:
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgwrote:
>Peter Nilsson <ai...@acay.com.auwrites:
DiAvOl <dia...@freemail.grwrote:
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) ks***@mib.org <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"
Oct 7 '08 #19

P: n/a
On Oct 7, 6:31 pm, Keith Thompson <ks...@mib.orgwrote:
vipps...@gmail.com 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 '08 #20

P: n/a
Nick Keighley <ni******************@hotmail.comwrote:
>
so is the program incorrect?
Yes, as far as C90 is concerned (but it is correct for C99).
Or did a particular version of gcc have a bug?
Also yes.
If the program is exhibiting UB then translating it and running it to
produce the "expected" behaviour is perfectly ok!
Which is the intended result with gcc, hence the characterization as a
gcc bug.
--
Larry Jones

Geez, I gotta have a REASON for everything? -- Calvin
Oct 7 '08 #21

P: n/a
Keith Thompson <ks***@mib.orgwrote:
>
I *think* that the behavior is undefined in both C90 and C99 (but
becomes well defined in C201X).
No, support for non-lvalue arrays was added in C99.
--
Larry Jones

Geez, I gotta have a REASON for everything? -- Calvin
Oct 7 '08 #22

P: n/a
la************@siemens.com writes:
Keith Thompson <ks***@mib.orgwrote:
>I *think* that the behavior is undefined in both C90 and C99 (but
becomes well defined in C201X).

No, support for non-lvalue arrays was added in C99.
Can you cite the section of the C99 standard that does this?

I see this in the list of major changes in the Foreword:

-- conversion of array to pointer not limited to lvalues

But C99 6.3.2.1p3 says:

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. If the
array object has register storage class, the behavior is
undefined.

The phrase "the array object" implies that there must be an array
object somewhere. In the case we're considering (the return value of
a function that returns a struct with an array member), there is no
array object whose initial element we can point to. Is there other
(normative) wording that clarifies this?

It seems that the new wording in n1336, creating an object with
"temporary lifetime" (6.2.4p7) is intended to avoid the need for
non-lvalue arrays.

My assumption is that you're right and that I've missed something.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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"
Oct 7 '08 #23

P: n/a
Keith Thompson <ks...@mib.orgwrote:
Peter Nilsson <ai...@acay.com.auwrites:
DiAvOl <dia...@freemail.grwrote:
#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.
On reflection, I conceed. It's not a bug; it's the worst
compiler 'feature' I've ever seen.

--
Peter
Oct 7 '08 #24

P: n/a
DiAvOl <dia...@freemail.grwrote:
Keith Thompson <ks...@mib.orgwrote:
...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?
It doesn't, since name doesn't decay to a pointer. Even
if it did, & requires an object. In other words, it works
by ub. Segfault is one example of ub, 'works just fine' is
another.

The question is why people went out of their way to cause
your sample to suddenly segfault. [Why they did a half
job is lesser question.]

--
Peter
Oct 7 '08 #25

P: n/a
Keith Thompson <ks***@mib.orgwrote:
>
The phrase "the array object" implies that there must be an array
object somewhere. In the case we're considering (the return value of
a function that returns a struct with an array member), there is no
array object whose initial element we can point to. Is there other
(normative) wording that clarifies this?
Yes, in N1336. :-)

In C90, the section you quoted said that only lvalues with array type
are converted to pointers; C99 relaxed that to allow all array type
expressions to be converted. As you note, that leads to a bit of
cognitive dissonance since an object suddenly appears in the midst of a
value, which doesn't otherwise happen. Nonetheless, you can safely
assume that it's magically created out of the luminiferous aether as
required and mysteriously evaporates again at the next sequence point.
The committee was loathe to say anything more about such objects since
it opens a can of worms (e.g., what storage duration and lifetime they
have), but we bit the bullet for C1X.
--
Larry Jones

In a minute, you and I are going to settle this out of doors. -- Calvin
Oct 7 '08 #26

P: n/a
la************@siemens.com writes:
Keith Thompson <ks***@mib.orgwrote:
>The phrase "the array object" implies that there must be an array
object somewhere. In the case we're considering (the return value of
a function that returns a struct with an array member), there is no
array object whose initial element we can point to. Is there other
(normative) wording that clarifies this?

Yes, in N1336. :-)

In C90, the section you quoted said that only lvalues with array type
are converted to pointers; C99 relaxed that to allow all array type
expressions to be converted. As you note, that leads to a bit of
cognitive dissonance since an object suddenly appears in the midst of a
value, which doesn't otherwise happen. Nonetheless, you can safely
assume that it's magically created out of the luminiferous aether as
required and mysteriously evaporates again at the next sequence point.
The committee was loathe to say anything more about such objects since
it opens a can of worms (e.g., what storage duration and lifetime they
have), but we bit the bullet for C1X.
Hmm.

So in C90, where the array-to-pointer conversion is defined only for
lvalues, ``make_person().name'' is an expression of array type. In
the code sample in the original post, it's passed as an argument to
printf, corresponding to a "%s" format, invoking undefined behavior.

In theory, I suppose, you could write a variadic function that
actually extracts an array value using va_arg -- though I'm not sure
what it could do with it, and I doubt that any implementations
actually support it.

I decline to believe that the phrase "the array object" in the C99
standard actually causes such an object to be created (or, more
precisely, imposes a requirement on implementers to arrange for such
an object to be created). In particular, I see no implied guarantee
that "the array object" will continue to exist until the next sequence
point. If the called function returns the value of an object of
struct type, then "the array object" could plausibly refer to the
array member of that object, which could be local to the function and
therefore nonexistent after the function returns.

I'm glad to see this is being corrected in C1x -- and I'll just avoid
writing such code in C90 or C99.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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"
Oct 7 '08 #27

P: n/a
DiAvOl wrote:
>
#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?
No. make_person() returns a struct by value, which has a field
identified by .name. That field is an array of 40 chars. It is a
portion of the return struct, which has never been put in
accessible memory.

Your alleged 'good' experience with lcc shows a bug in lcc. I
don't know if you mean lcc-win32 (which has quite a few known
insects) or lcc (which is less well known here).

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 7 '08 #28

P: n/a
DiAvOl wrote:
Keith Thompson <ks...@mib.orgwrote:
>DiAvOl <dia...@freemail.grwrote:
[...]
>>
>>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?
Please don't strip attributions for any material you quote. I
restored the third one above.

The point is that you have undefined behaviour. Defining why it
works on your particular system would require complete analysis of
the running system, after which you MIGHT know when it wouldn't
work. Until you use a different issue of the compiler, library,
optimizations, etc.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 7 '08 #29

P: n/a
CBFalconer <cbfalco...@yahoo.comwrote:
DiAvOl wrote:
#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?

No. *make_person() returns a struct by value, which has a
field identified by .name. *That field is an array of 40
chars. *It is a portion of the return struct, which has
never been put in accessible memory.

Your alleged 'good' experience with lcc shows a bug in
lcc.
What bug does it show?

--
Peter
Oct 7 '08 #30

P: n/a
Keith Thompson wrote:
>
.... snip ...
>
But C99 6.3.2.1p3 says:

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. If the array object has register storage
class, the behavior is undefined.

The phrase "the array object" implies that there must be an array
object somewhere. In the case we're considering (the return
value of a function that returns a struct with an array member),
there is no array object whose initial element we can point to.
Is there other (normative) wording that clarifies this?

It seems that the new wording in n1336, creating an object with
"temporary lifetime" (6.2.4p7) is intended to avoid the need for
non-lvalue arrays.

My assumption is that you're right and that I've missed something.
I don't think so. Remember that n1336 is not the C99 standard, but
a draft for a new C0x system. I don't believe that any 'temporary
lifetime' storage for function results will survive - it will
involve too many ugly inefficiencies.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 7 '08 #31

P: n/a
Martin Ambuhl wrote:
Nick Keighley wrote:
><lovecreatesbea...@gmail.comwrote:
>>Keith Thompson <ks...@mib.orgwrote:
<lovecreatesbea...@gmail.comwrites:
DiAvOl <dia...@freemail.grwrote:
>
>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.
Therefore it would be useful for DiAv01 to report the compiler
version he used, and on what system it was running.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 7 '08 #32

P: n/a
Nick Keighley wrote:
Martin Ambuhl <mamb...@earthlink.netwrote:
.... snip ...
>
>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!
The program is incorrect. There is no requirement for UB to cause
an error message.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 7 '08 #33

P: n/a
jacob navia wrote:
DiAvOl wrote:
.... snip ...
>
>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.
No, lcc-win's UB is such as to hide the problem.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 7 '08 #34

P: n/a
On Tue, 07 Oct 2008 19:12:22 -0400,
CBFalconer <cb********@yahoo.comwrote:
DiAvOl wrote:
The OP wrote, which you snipped, but responded to:
>PS. I tried the lcc compiler which compiled the code without
warnings/errors
Your alleged 'good' experience with lcc shows a bug in lcc. I
don't know if you mean lcc-win32
Can you explain why that is a bug in lcc or lcc-win32?

It seems to me after reading this thread -- particularly the posts by
Larry Jones -- that the behaviour under c89 for that code is undefined,
which means that producing the expected behaviour is perfectly valid. It
also appears that under c99 the code is defined, and is supposed to
produce the expected behaviour.

Since the lcc compiler that the OP used produces the expected behaviour
(printing the string "alexander"), which is valid behaviour under both
c89 and c99, how can there be a bug?

Did you mean that a diagnostic was required? If so, can you explain why?

Martien
--
|
Martien Verbruggen | If at first you don't succeed, try again.
| Then quit; there's no use being a damn fool
| about it.
Oct 7 '08 #35

P: n/a
CBFalconer <cb********@yahoo.comwrites:
DiAvOl wrote:
>>
#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?

No. make_person() returns a struct by value, which has a field
identified by .name. That field is an array of 40 chars. It is a
portion of the return struct, which has never been put in
accessible memory.

Your alleged 'good' experience with lcc shows a bug in lcc. I
don't know if you mean lcc-win32 (which has quite a few known
insects) or lcc (which is less well known here).
What bug are you referring to? In another followup in this thread,
you said that the program's behavior is undefined; if so, anything
lcc-win does is permitted, and in this particular case its behavior
seems reasonable.

Larry Jones says that the stated behavior of lcc (or lcc-win) is what
was intended for C99. I'm skeptical that the C99 standard actually
states this, but N1336, the first draft for C1X, makes it explicit
that there is a temporary object. (It might arguably be a constraint
violation in C90, but lcc-win doesn't claim to support C90.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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"
Oct 7 '08 #36

P: n/a
CBFalconer <cb********@yahoo.comwrites:
Keith Thompson wrote:
>>
... snip ...
>>
But C99 6.3.2.1p3 says:

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. If the array object has register storage
class, the behavior is undefined.

The phrase "the array object" implies that there must be an array
object somewhere. In the case we're considering (the return
value of a function that returns a struct with an array member),
there is no array object whose initial element we can point to.
Is there other (normative) wording that clarifies this?

It seems that the new wording in n1336, creating an object with
"temporary lifetime" (6.2.4p7) is intended to avoid the need for
non-lvalue arrays.

My assumption is that you're right and that I've missed something.

I don't think so. Remember that n1336 is not the C99 standard, but
a draft for a new C0x system.
Yes, I know what n1336 is. (It's C201X, BTW, or C1X if you want to be
terse; the final document presumably won't be ready before the end of
next year.)
I don't believe that any 'temporary
lifetime' storage for function results will survive - it will
involve too many ugly inefficiencies.
How so? It seems to me that the most natural way to implement a
function returning a struct value involves, in effect, creating an
object of the struct type somewhere in memory and setting it to the
value to be returned. In fact, unless the struct is no bigger than a
machine word, I'm having trouble thinking of an plausible
implementation scheme that doesn't do this.

The current C standard doesn't mention such an object, so it doesn't
necessarily exist *as an object*. In the abstract machine, there's
just a struct value floating around somewhere. This causes serious
conceptual problems for this corner case. where a reference to an
array member of this struct value *needs* the object to exist.

The proposed change for C201X makes this object explicit, but only
when the struct (or union; I just noticed that) has an array member.

As far as I can tell, this only affects a function returning a struct
with an array member, something that I think is fairly rare; it's more
common to deal with structs, especially large ones, by passing
pointers around. And it's likely to mandate what many compilers
already do.

Where are the "ugly inefficiencies"? And what's your proposed
alternative to the temporary object? Would you leave the behavior of
this corner case undefined?

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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"
Oct 8 '08 #37

P: n/a
CBFalconer wrote:
Martin Ambuhl wrote:
>Nick Keighley wrote:
>><lovecreatesbea...@gmail.comwrote:
Keith Thompson <ks...@mib.orgwrote:
<lovecreatesbea...@gmail.comwrites:
>DiAvOl <dia...@freemail.grwrote:
>>
>>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.

Therefore it would be useful for DiAv01 to report the compiler
version he used, and on what system it was running.
No, I misunderstood. He is *not* using -std=c99 and attempting to use a
c99 construct. I misread 'without' as 'with' in
The above small program when compiled without the -std=c99 option
This reading error was probably triggered by my inability to realize
that someone might try to use a c99-only construct in a c89 environment
and then ask why it didn't work.
Oct 8 '08 #38

P: n/a
On Oct 8, 3:24*am, Martin Ambuhl <mamb...@earthlink.netwrote:
CBFalconer wrote:
Martin Ambuhl wrote:
Nick Keighley wrote:
<lovecreatesbea...@gmail.comwrote:
Keith Thompson <ks...@mib.orgwrote:
<lovecreatesbea...@gmail.comwrites:
DiAvOl <dia...@freemail.grwrote:
>>>>>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.
Therefore it would be useful for DiAv01 to report the compiler
version he used, and on what system it was running.

No, I misunderstood. *He is *not* using -std=c99 and attempting to use a
c99 construct. *I misread 'without' as 'with' in
*The above small program when compiled without the -std=c99 option
This reading error was probably triggered by my inability to realize
that someone might try to use a c99-only construct in a c89 environment
and then ask why it didn't work.
That is exactly the reason I asked, to understand why it works for C99
and not for C89

I won't use such a construct in C89 of course, I'm trying to
understand (and I think i do understand now) why it works (or does
not!!) this way in C89

Why is this hard to understand?
Oct 8 '08 #39

P: n/a
DiAvOl <di****@freemail.grwrites:
On Oct 8, 3:24*am, Martin Ambuhl <mamb...@earthlink.netwrote:
>CBFalconer wrote:
Martin Ambuhl wrote:
Nick Keighley wrote:
<lovecreatesbea...@gmail.comwrote:
Keith Thompson <ks...@mib.orgwrote:
<lovecreatesbea...@gmail.comwrites:
>DiAvOl <dia...@freemail.grwrote:
>>>>>>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.
Therefore it would be useful for DiAv01 to report the compiler
version he used, and on what system it was running.

No, I misunderstood. *He is *not* using -std=c99 and attempting to use a
c99 construct. *I misread 'without' as 'with' in
*The above small program when compiled without the -std=c99 option
This reading error was probably triggered by my inability to realize
that someone might try to use a c99-only construct in a c89 environment
and then ask why it didn't work.

That is exactly the reason I asked, to understand why it works for C99
and not for C89

I won't use such a construct in C89 of course, I'm trying to
understand (and I think i do understand now) why it works (or does
not!!) this way in C89
In C89/C90, the implicit conversion of an expression of array type to
a pointer to the array object's first element occurs only
when the array expression is an lvalue. Quoting the C90 standard:

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 element of the array object and is not an lvalue.

Your array expression "make_person().name" is not an lvalue, so the
conversion doesn't occur. It's unclear what happens next. I *think*
you're passing the array by value to printf, which normally isn't
possible; since printf is expecting a char* due to the "%s" format,
the behavior is undefined. But when you assign the result of
make_person() to the object p, the expression p.name *is* an lvalue,
the conversion does occur, and everything works.

C99 drops the requirement for the array expression to be an lvalue, so
the array-to-pointer conversion does occur, even for
"make_person().name". The problem, though, is that it's not at all
clear what "the array object" is. Arguably if there's no lvalue, then
there's no array object, and the standard's requirement is
meaningless.

C1X proposes to create an implicit temporary object in this case, so
"make_person().name" *is* an lvalue. It's been suggested that this
was the intent for C99, but I'm not convinced -- but perhaps the
authors of gcc were convinced.

Arrays in C are almost always treated as second-class objects. It's
almost impossible to obtain an expression of array type that doesn't
refer to an array object. I believe this can *only* occur when the
array is a member of a struct or union, and that struct or union is
returned from a function -- which is itself the only way (I think) to
obtain an expression of struct or union type that doesn't refer to an
object of struct or union type.

Whether accidentally or deliberately, you've run into an obscure
corner of the language where even the experts don't necessarily agree
on what's supposed to happen. Your best bet, if you're actually
trying to get some work done, is to avoid the issue and use an
explicit temporary.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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"
Oct 8 '08 #40

P: n/a
Keith Thompson wrote:
CBFalconer <cb********@yahoo.comwrites:
.... snip ...
>
>I don't believe that any 'temporary lifetime' storage for
function results will survive - it will involve too many ugly
inefficiencies.

How so? It seems to me that the most natural way to implement
a function returning a struct value involves, in effect,
creating an object of the struct type somewhere in memory and
setting it to the value to be returned. In fact, unless the
struct is no bigger than a machine word, I'm having trouble
thinking of an plausible implementation scheme that doesn't do
this.
Because most C systems simply return function values in a specified
register. If the user wants to ignore that value he just doesn't
use it. If he wants to use it, it is already in place. The
storage feature would require storing all those values somewhere,
just to all a field access. Now the optimizer will have to work
like mad to eliminate all those additions. This is very rough, and
just as I see it immediately. Notice that the lack of action
(ignoring the return value) involves releasing that storage. Ugh.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 8 '08 #41

P: n/a
Peter Nilsson wrote:
CBFalconer <cbfalco...@yahoo.comwrote:
.... snip ...
>
>No. make_person() returns a struct by value, which has a
field identified by .name. That field is an array of 40
chars. It is a portion of the return struct, which has
never been put in accessible memory.

Your alleged 'good' experience with lcc shows a bug in
lcc.

What bug does it show?
You're right. There is no requirement for a message about UB.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 8 '08 #42

P: n/a
CBFalconer <cb********@yahoo.comwrites:
Keith Thompson wrote:
>CBFalconer <cb********@yahoo.comwrites:
... snip ...
>>
>>I don't believe that any 'temporary lifetime' storage for
function results will survive - it will involve too many ugly
inefficiencies.

How so? It seems to me that the most natural way to implement
a function returning a struct value involves, in effect,
creating an object of the struct type somewhere in memory and
setting it to the value to be returned. In fact, unless the
struct is no bigger than a machine word, I'm having trouble
thinking of an plausible implementation scheme that doesn't do
this.

Because most C systems simply return function values in a specified
register. If the user wants to ignore that value he just doesn't
use it. If he wants to use it, it is already in place. The
storage feature would require storing all those values somewhere,
just to all a field access. Now the optimizer will have to work
like mad to eliminate all those additions. This is very rough, and
just as I see it immediately. Notice that the lack of action
(ignoring the return value) involves releasing that storage. Ugh.
I'm trying to follow this discussion and not succeeding. If I
understand you correctly, what you're trying to avoid is what already
happens. Calling conventions usually do specify that the return value
goes in a certain register, *if* it is of a type appropriate to fit in
that register. But most structs will not fit in a register, so there
is no alternative to storing the return value in memory somewhere.
Normally the calling function allocates space on the stack.
"Releasing the storage" is very easy because it happens automatically
when the function returns.

You are correct in that it needs to allocate this space even if the
return value is going to be ignored. But again, this is already the
case. As I understand it, the only difference between the current
state of affairs and what's proposed for C1x is how long the compiler
has to keep the return value intact before it can write over it.

Are you proposing to do away entirely with the ability to return
structs from C functions? Given the problems that arise, one might
argue that adding them to C was ill-considered, but I think it's too
late to take them back now.
Oct 8 '08 #43

P: n/a
On 8 Oct, 00:39, CBFalconer <cbfalco...@yahoo.comwrote:
Nick Keighleywrote:
Martin Ambuhl <mamb...@earthlink.netwrote:
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!

The program is incorrect. *There is no requirement for UB to cause
an error message.
sorry? If its UB it can anything it likes. There may be no
requirement
to produce an error message (a diagnostic) but there can't be
anything
wrong with producing a diagnostic. So why is (this version) of gcc
buggy?

--
Nick Keighley
Oct 8 '08 #44

P: n/a
On 8 Oct, 00:41, CBFalconer <cbfalco...@yahoo.comwrote:
jacob navia wrote:
DiAvOl wrote:
If I've understood the rest of the thread. This is Undefined
Behaviour.
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.
how can it be "correct" if its Undefined Behaviour?
Is lcc operating in C89 or C99 mode?

No, lcc-win's UB is such as to hide the problem.
what problem? If it's UB it can what it likes. That's what
UB is for, to make life easy for implementors.

And to be honest printing the string seems like the sanest
possible implementation.

--
Nick Keighley

Oct 8 '08 #45

P: n/a
On Oct 8, 5:59 am, Peter Nilsson <ai...@acay.com.auwrote:
DiAvOl <dia...@freemail.grwrote:
Keith Thompson <ks...@mib.orgwrote:
...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?

It doesn't, since name doesn't decay to a pointer. Even
It seems it's still an array :)

int main(void) {

/* printf("%s\n", make_person().name); */

size_t n = sizeof make_person().name;
size_t i;

printf("%d\n", n);
for (i = 0; i < n; i++)
printf("%c", make_person().name[i]);
return 0;
}

$ gcc --version
gcc (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There
is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

$ make && ./a.out
gcc -ansi -pedantic -Wall -W -c -o a.o a.c
a.c: In function ‘main’:
a.c:24: warning: ISO C90 forbids subscripting non-lvalue array
gcc a.o -o a.out
40
alexander$
$
>
if it did, & requires an object. In other words, it works
by ub. Segfault is one example of ub, 'works just fine' is
another.

The question is why people went out of their way to cause
your sample to suddenly segfault. [Why they did a half
job is lesser question.]
Oct 8 '08 #46

P: n/a
On 8 Oct 2008 at 5:22, Nate Eldredge wrote:
CBFalconer <cb********@yahoo.comwrites:
[bullshit]
I'm trying to follow this discussion and not succeeding.
That's because it's bullshit, for the reasons you go on to describe very
articulately.

You should bear in mind that CBF is a senile old fool who doesn't have
the first clue what he's talking about. No one here takes him seriously
- even the usually mild-mannered KT is currently laying into his
stupidity in repeating replies others have made hours earlier.

Oct 8 '08 #47

P: n/a
Antoninus Twink wrote:
On 8 Oct 2008 at 5:22, Nate Eldredge wrote:
>CBFalconer <cb********@yahoo.comwrites:
[bullshit]
>I'm trying to follow this discussion and not succeeding.

That's because it's bullshit,
EXACTLY
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Oct 8 '08 #48

P: n/a
Nick Keighley wrote:
On 8 Oct, 00:39, CBFalconer <cbfalco...@yahoo.comwrote:
>Nick Keighleywrote:
....
>>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!
The program is incorrect. There is no requirement for UB to cause
an error message.

sorry? If its UB it can anything it likes. There may be no
requirement
to produce an error message (a diagnostic) but there can't be
anything
wrong with producing a diagnostic. So why is (this version) of gcc
buggy?
He said "the program is incorrect". How did you manage to misinterpret
that as a statement that gcc is buggy?
Oct 8 '08 #49

P: n/a
Nick Keighley wrote:
On 8 Oct, 00:41, CBFalconer <cbfalco...@yahoo.comwrote:
>jacob navia wrote:
>>DiAvOl wrote:

If I've understood the rest of the thread. This is Undefined
Behaviour.
>>>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.

how can it be "correct" if its Undefined Behaviour?
All behavior is correct when the behavior is not defined by the
standard. However, what jacob means by "correct" is somewhat more
restrictive: it behaves in the manner that a reasonable person (as
judged from jacob's perspective) would expect it to work.
Is lcc operating in C89 or C99 mode?
He's talking about lcc-win, not lcc. lcc-win has no mode in which it
fully conforms to either standard. Incidentally, the behavior produced
by lcc-win is the same as that specified by the proposed draft for the
next version of the standard, and arguably the same behavior that was
intended to be correct in C99. That gives the term "correct" a little
more appropriateness. However, I suspect that this is just a coincidence.
Oct 8 '08 #50

160 Replies

This discussion thread is closed

Replies have been disabled for this discussion.