473,554 Members | 3,443 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Returning a struct from a function - strange behavior

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(voi d);

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

return 0;
}

static Person make_person(voi d) {
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().n ame); with
printf("%s\n", &make_person(). name[0]); everything works as expected.

Why does this happen? Isn't make_person().n ame 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().n ame 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
160 5773
Nick Keighley wrote:
On 7 Oct, 09:28, "lovecreatesbea ...@gmail.com"
<lovecreatesbea ...@gmail.comwr ote:
>On Oct 7, 2:57 pm, Keith Thompson <ks...@mib.orgw rote:


>>"lovecreatesb ea...@gmail.com " <lovecreatesbea ...@gmail.comwr ites:
On Oct 7, 9:23 am, DiAvOl <dia...@freemai l.grwrote:
int main(void) {
printf("%s\n", make_person().n ame);
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().n ame);*/
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
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgw rote:
[...]
An lvalue is only explicitly required in C90. But in either
case, make_person().n ame is an lvalue.

I don't believe it is. *make_person() yields a value of type Person.
make_person().a ge 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
On 7 Oct, 10:01, Martin Ambuhl <mamb...@earthl ink.netwrote:
Nick Keighley wrote:
On 7 Oct, 09:28, "lovecreatesbea ...@gmail.com"
<lovecreatesbea ...@gmail.comwr ote:
On Oct 7, 2:57 pm, Keith Thompson <ks...@mib.orgw rote:
>"lovecreatesbe a...@gmail.com" <lovecreatesbea ...@gmail.comwr ites:
On Oct 7, 9:23 am, DiAvOl <dia...@freemai l.grwrote:
int main(void) {
* printf("%s\n", make_person().n ame);
* 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().n ame);*/
* * * * 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
On Tue, 07 Oct 2008 05:01:25 -0400,
Martin Ambuhl <ma*****@earthl ink.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
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgw rote:
Peter Nilsson <ai...@acay.com .auwrites:
DiAvOl <dia...@freemai l.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(voi d);
int main(void) {
printf("%s\n", make_person().n ame);
return 0;
}
static Person make_person(voi d) {
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().a ge yields a value of type int. make_person().n ame
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
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
On 7 Oct, 14:53, vipps...@gmail. com wrote:
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgw rote:
Peter Nilsson <ai...@acay.com .auwrites:
DiAvOl <dia...@freemai l.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(voi d);
>int main(void) {
> printf("%s\n", make_person().n ame);
> return 0;
>}
>static Person make_person(voi d) {
> 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().a ge yields a value of type int. make_person().n ame
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
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.orgw rote:
Peter Nilsson <ai...@acay.com .auwrites:
DiAvOl <dia...@freemai l.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(voi d);
int main(void) {
printf("%s\n", make_person().n ame);
return 0;
}
static Person make_person(voi d) {
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().a ge yields a value of type int. make_person().n ame
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
vi******@gmail. com writes:
On Oct 7, 9:50 am, Keith Thompson <ks...@mib.orgw rote:
>Peter Nilsson <ai...@acay.com .auwrites:
DiAvOl <dia...@freemai l.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(voi d);
>int main(void) {
printf("%s\n", make_person().n ame);
return 0;
}
>static Person make_person(voi d) {
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_Keit h) 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
On Oct 7, 6:31 pm, Keith Thompson <ks...@mib.orgw rote:
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

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
3225
by: I.M. !Knuth | last post by:
Hi. I'm more-or-less a C newbie. I thought I had pointers under control until I started goofing around with this: ================================================================================ /* A function that returns a pointer-of-arrays to the calling function. */ #include <stdio.h> int *pfunc(void);
0
7506
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8018
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
7872
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
6123
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5423
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5142
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3545
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3533
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
823
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.