aggregate return warnings

M

markn

Running some code through static analysis, I noticed that gcc will
generate a warning if a function returns an aggregate, controlled with
this flag (from the gcc manual):

-Waggregate-return
Warn if any functions that return structures or unions are defined
or called. (In languages where you can return an array, this also
elicits a warning.)

Easy enough to disregard, but I'm trying to understand the rationale.
Were aggregate returns not allowed in K&R? Is there some other good
reason for this warning?

I guess you might want to know about this if you were writing a
library that returns values to some other language, but that seems
like kind of a weak reason for a warning message. If you were using
that justification, you could end up generating warnings for just
about any otherwise normal behavior.

Thanks.

|
| Mark Nelson - http://marknelson.us
|
 
G

Gianni Mariani

Running some code through static analysis, I noticed that gcc will
generate a warning if a function returns an aggregate, controlled with
this flag (from the gcc manual):

-Waggregate-return
Warn if any functions that return structures or unions are defined
or called. (In languages where you can return an array, this also
elicits a warning.)

Easy enough to disregard, but I'm trying to understand the rationale.
Were aggregate returns not allowed in K&R? Is there some other good
reason for this warning?

I guess you might want to know about this if you were writing a
library that returns values to some other language, but that seems
like kind of a weak reason for a warning message. If you were using
that justification, you could end up generating warnings for just
about any otherwise normal behavior.

I imagine that if you were creating a cross platform library and one of
the target platforms did not support this feature (aggregate returns
were not available on some compilers - a long time ago at least I
remember some compilers not supporting it), then you can at least
maintain the product on a gcc compiler WRT to this feature anyway.
 
V

Victor Bazarov

Running some code through static analysis, I noticed that gcc will
generate a warning if a function returns an aggregate, controlled with
this flag (from the gcc manual):

-Waggregate-return
Warn if any functions that return structures or unions are defined
or called. (In languages where you can return an array, this also
elicits a warning.)

Easy enough to disregard, but I'm trying to understand the rationale.
Were aggregate returns not allowed in K&R? Is there some other good
reason for this warning?

I guess you might want to know about this if you were writing a
library that returns values to some other language, but that seems
like kind of a weak reason for a warning message. If you were using
that justification, you could end up generating warnings for just
about any otherwise normal behavior.

My guess would be that the best information about this you will obtain
by asking in a GCC forum. K&R (although fun to discuss, maybe) is not
really topical here, try comp.lang.c.

V
 
M

modemer

The good reason to raise this warning is to let the programmer know
the stack would be potentially overflowed if you return a big object.

cheers
 
F

faceman28208

Easy enough to disregard, but I'm trying to understand the rationale.
Were aggregate returns not allowed in K&R? Is there some other good
reason for this warning?

Most systems have a "calling standard" that defines how parameters are
exchanged among functions.Traditionally, function return values are
returned in registers.

When a function attempts to return an a aggregate, it is usually
impossible to return the structure through the designated return
registers (most compilers won't try even if the structure is small
enough).

What the compiler generally has to do is create a dummy parameter and
return the value that way.

1. This usually disrupts the "calling standard". Thus, such a function
may become uncallable from a module created by another compiler.

2. While I hate to discuss efficiency in code, passing and returning
aggregates by value is probably the most inefficient avoidable coding
practice.

3. It suggests something is wrong in your design.
 
J

jg

Most systems have a "calling standard" that defines how parameters are
exchanged among functions.Traditionally, function return values are
returned in registers.

When a function attempts to return an a aggregate, it is usually
impossible to return the structure through the designated return
registers (most compilers won't try even if the structure is small
enough).

What the compiler generally has to do is create a dummy parameter and
return the value that way.

1. This usually disrupts the "calling standard". Thus, such a function
may become uncallable from a module created by another compiler.

The right term for calling stardard is ABI (application Binary
Interface).
The different compilers can generate compatible code if they follows
the same ABI.
2. While I hate to discuss efficiency in code, passing and returning
aggregates by value is probably the most inefficient avoidable coding
practice.
I think efficiency is the issue here. Usually, a compiler allocates a
space
in caller for returning struct value and passes that address to
callee. This
usually isn't efficient. A user can do a better job here.


JG
 
P

peter koch

The right term for calling stardard is ABI (application Binary
Interface).
The different compilers can generate compatible code if they follows
the same ABI.


I think efficiency is the issue here. Usually, a compiler allocates a
space
in caller for returning struct value and passes that address to
callee. This
usually isn't efficient.
Why? What is inefficient about this scheme? In practice the overhead
is one instruction (pushing a pointer), and I doubt it can be done any
better.
A user can do a better job here.

How? In general, (N)RVO makes returning structures more efficient than
possible for the user (at least without lots of hacking on the way),
and the new move-types in C++0x will further improve this. In short,
returning structures is not inefficient and can't be improved on by
the programmer.

/Peter
 
B

Branimir Maksimovic

Running some code through static analysis, I noticed that gcc will
generate a warning if a function returns an aggregate, controlled with
this flag (from the gcc manual):

-Waggregate-return
Warn if any functions that return structures or unions are defined
or called. (In languages where you can return an array, this also
elicits a warning.)

Easy enough to disregard, but I'm trying to understand the rationale.
Were aggregate returns not allowed in K&R? Don't know
Is there some other good
reason for this warning?

Actually it is. When writing inline assembly or interfacing
with other languages (or even C++ compiler),
one usually relies on calling convention,
and by that I mean order, number, and type of parameters.
Usually return value from function is passed through
machine register. If register is not large enough to
hold return value, compiler usually adds one hidden parameter
to function, which is pointer to memory where result should
be stored. This completely changes prototype of function,
as there is additional parameter, so external code calling
this function ,but not knowing this, may fail. Therefore
this warning is very useful in such situations.

Greetings, Branimir.
 
B

Branimir Maksimovic

Huh, I didn;t saw replies, sorry for redundant post.

Greetings, Branimir.
 
M

markn

Thanks all.

I'd have to say that there's nothing too convincing here. I can see
why the rare user might want the warning, but it's for such generally
obscure reasons I can't really see building it into a product.
Actually it is. When writing inline assembly or interfacing
with other languages (or even C++ compiler),
one usually relies on calling convention,

Sure, but when one is using inline assembly or is writing a library to
be used by another language, your API is always right there in your
face. In general you're usually hand coding the interface to some
other language at the same time you're writing the C++ function. You
don't need the compiler to warn you that you're returning an
aggregrate when your calling convention won't support it. And if
you're using inline assembly to look at the return value, you're not
going to really expect some monster structure to be present in eax or
whatever. Are you?
I think efficiency is the issue here.

Maybe, but I'm skeptical on that. I think the compiler can generate
code that looks just about the same as you would. And in any case, a
minor efficiency point isn't usually worth a warning. Again, if that
was the case, you could start writing new warnings to no end.

And maybe it's just me, but I personally like this:

foo a = get_the_next_foo();

better than:

foo a;
get_the_next_foo( a );

Cuts my lines of code by 50%, and it really drives home that "declare
at first use", doesn't it?
K&R (although fun to discuss, maybe) is not
really topical here, try comp.lang.c.

Somebody always wants to be the first to call you for OT. It is C++,
it is a C++ compiler, and the question is a generic C++ question. Yes,
the warning message is issued by g++, but I was asking about the
rationale wrt. the language, not the implementation. Okay, you did get
in first though.
The good reason to raise this warning is to let the programmer know
the stack would be potentially overflowed if you return a big object.

Quite a stretch to imagine that. And of course, the compiler knows how
big the structure is, there is certainly room for heuristics here. If
this rationale was good, the compiler would have exactly the same
reason to flag this with a warning:

void foo()
{
bar x;

In that case, the auto declaration of x could overflow the stack.
3. It suggests something is wrong in your design.

Pray tell, master.

|
| Mark Nelson - http://marknelson.us
|
 
J

jg

Why? What is inefficient about this scheme? In practice the overhead
is one instruction (pushing a pointer), and I doubt it can be done any
better.

Probably more than one instruction. For example:

Given the following code:
struct T {...} t;

t = foo(...);

A compiler will do the following:
struct T tmp;
foo(&tmp,...)
t = tmp; // struct assignment

Also, within foo(...), tmp is assigned right before return from foo,
which
may be another struct assignment (calling ctor for C++). If a user
writes foo
as:
foo (T *x...)

Those two struct assignments are no longer needed.



JG
 
P

peter koch

Probably more than one instruction. For example:

Given the following code:
struct T {...} t;

t = foo(...);

This is not the normal way to write your code. You would normally
initialise when constructing t.
A compiler will do the following:
struct T tmp;
foo(&tmp,...)
t = tmp; // struct assignment

Not exactly, as your definition of tmp will not involve a constructor
call. The pseudocode shown above will only allocate storage for tmp,
calling the constructor from inside foo.
Also, within foo(...), tmp is assigned right before return from foo,
Normally not if (N)RVO is used (and all compilers I know do use that
trick).
which
may be another struct assignment (calling ctor for C++). If a user
writes foo
as:
foo (T *x...)

Those two struct assignments are no longer needed.
There are not two assignments - there is only one. And in your code
where you pass T as a reference (I assume your pointer was meant to be
a reference), you will have to do the assignment yourself - in the
general case by creating a local instance of type T unless you can
cope with the change in semantics (that might result in case e.g. an
exception is thrown).

/Peter
 
R

Ron Natalie

Easy enough to disregard, but I'm trying to understand the rationale.
Were aggregate returns not allowed in K&R? Is there some other good
reason for this warning?

I believe K&R covered aggregate returns, but the earliest C compilers
(Version 6 unix for example) surely DID NOT handle it. However,
goofy G++ compiler switches are off topic here. With at least the 3.x
they made normal C++ behavior the default so you rarely much touch the
-f switches to get real work done.
 
P

peter koch

Thanks all.

I'd have to say that there's nothing too convincing here. I can see
why the rare user might want the warning, but it's for such generally
obscure reasons I can't really see building it into a product.


Sure, but when one is using inline assembly or is writing a library to
be used by another language, your API is always right there in your
face. In general you're usually hand coding the interface to some
other language at the same time you're writing the C++ function. You
don't need the compiler to warn you that you're returning an
aggregrate when your calling convention won't support it. And if
you're using inline assembly to look at the return value, you're not
going to really expect some monster structure to be present in eax or
whatever. Are you?


Maybe, but I'm skeptical on that. I think the compiler can generate
code that looks just about the same as you would. And in any case, a
minor efficiency point isn't usually worth a warning. Again, if that
was the case, you could start writing new warnings to no end.

And maybe it's just me, but I personally like this:

foo a = get_the_next_foo();

better than:

foo a;
get_the_next_foo( a );

Cuts my lines of code by 50%, and it really drives home that "declare
at first use", doesn't it?
In my opinion your argument simply demonstrates that you have
understood what C++ is about.

/Peter
[snip]
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,294
Messages
2,571,511
Members
48,216
Latest member
DarrelLho

Latest Threads

Top