semicon@watsci.uwaterloo.ca (Robert Adsett) (02/24/90)
I ran into a problem with my compiler (it claims to be ANSI
compliant) the other day while using the const keyword. I'd like to
know if whether I've run into a compiler bug or my understanding of
the const keyword is incomplete. The problem shows up in the code
fragment that follows.
#include <math.h>
struct qwert { int a; double b;};
void asdf( struct qwert a);
const double a = 3.0;
void junk( const double *b, const struct qwert *c)
{
(void)exp(a); /* Works */
(void)exp(*b); /* Works */
asdf( *c); /* Type mismatch ???? */
}
The compiler gives a type mismatch in argument error for the line
indicated. If I either add const to the prototype or remove it from
the argument to junk it compiles without error. Is there some reason
that 'const double *b' should be treated differently from 'const
struct qwert *c'? Surely it's not possible for a structure that's
passed by value to be changed by the called function?
--
Robert Adsett <semicon@watsci.UWaterloo.ca>
Dept. of Phys, Univ. of Waterloo, Waterloo Ont. Canada
CMH117@psuvm.psu.edu (Charles Hannum) (02/24/90)
The double is passed by value; so dereferencing it works fine. But the struct is passed by reference (as are *all* structures in C!). In reality, you need to pass a "struct qwert *" to the function. Normally, the compiler takes the reference automatically, but you are trying to do this in reverse. Thus, it does not work; you simply can't pass a structure by value. Virtually, - Charles Martin Hannum II "Klein bottle for sale ... inquire within." (That's Charles to you!) "To life immortal!" cmh117@psuvm.{bitnet,psu.edu} "No noozzzz izzz netzzzsnoozzzzz..." c9h@psuecl.{bitnet,psu.edu} "Mem'ry, all alone in the moonlight ..."
randy@csseq.tamu.edu (Randy Hutson) (02/24/90)
In message <90054.232325CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes: >The double is passed by value; so dereferencing it works fine. But the >struct is passed by reference (as are *all* structures in C!). In reality, >you need to pass a "struct qwert *" to the function. Normally, the compiler >takes the reference automatically, but you are trying to do this in reverse. >Thus, it does not work; you simply can't pass a structure by value. The original poster said his compiler claimed to be ANSI compliant. ANSI C allows structures to be assigned, returned by functions, and passed by value to functions. However, some non-ANSI compilers may do as you have said with struct function arguments.
will@charyb.COM (Will Crowder) (02/25/90)
In article <90054.232325CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes: > >The double is passed by value; so dereferencing it works fine. But the >struct is passed by reference (as are *all* structures in C!). In reality, >you need to pass a "struct qwert *" to the function. Normally, the compiler >takes the reference automatically, but you are trying to do this in reverse. >Thus, it does not work; you simply can't pass a structure by value. Uh, yes you can. The man is using what claims to be an ANSI C compiler (apparently, a slightly broken one), and there is nothing special about structure objects in ANSI C (at least in terms of how they are passed to a function). From 3.1.2.5 of the 12/88 draft: "Any number of derived types can be constructed from the object, function, and incomplete types, as follows:" ... "* A structure type describes a sequentially allocated nonempty set of member objects, each of which has an optionally specified name and possibly distinct type." The point is, a structure is an object just like any other object; there is no special constraint on it of the type you describe. The draft Standard goes on to describe what happens on entry to a function: Section 3.7.1: "On entry to the function the value of each argument expression shall be converted to the type of its corresponding parameter, as if by assignment to the parameter. Array expressions and function designators as arguments are converted to pointers before the call." Structures are neither array objects nor function objects, and thus may be passed by value. gcc -pedantic -Wall -c his.c.file.c -o /dev/nul produces no warnings or errors for his code. However, Turbo C 2.0 seems to have the problem he is describing: Warning [...]: Structure passed by value... Error [...]: Type mismatch in parameter 'a' in call to 'asdf'... Changing the prototype to "const struct qwert a" fixes the error, but does not remove the warning. The compiler is warning that it specifically *is* an ANSI C compiler, and will pass structures by value unless told to do otherwise with the & operator. UNIX compilers traditionally converted such references to pointers, so if someone is using Turbo C to port some UNIX code, this is a very useful warning. Actually, I'm somewhat surprised that Turbo C didn't just throw out the "const" in: void asdf(const struct qwert a); I wouldn't think "const" would mean much for a non-pointer parameter passed by value. Will
gwyn@smoke.BRL.MIL (Doug Gwyn) (02/25/90)
In article <90054.232325CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes: >The double is passed by value; so dereferencing it works fine. But the >struct is passed by reference (as are *all* structures in C!). In reality, >you need to pass a "struct qwert *" to the function. Normally, the compiler >takes the reference automatically, but you are trying to do this in reverse. >Thus, it does not work; you simply can't pass a structure by value. You shouldn't answer questions when you don't know what you're talking about. Structure arguments to functions are passed by value, not by reference. The implementation may play funny games that amount to building a private copy of the structure and passing a reference to the private copy, but from the point of view of the programmer the structure is passed by value and has exactly the properties one would expect for the by-value mechanism. The compiler was correct to complain about an argument that had as its type "pointer to qualified type" being passed to a function expecting a pointer to an unqualified type. That violates 3.3.16.1 (as referred to in 3.3.2.2); and that is a logical constraint for the standard to have imposed, because the function may try to store into the pointed-to location but since the pointed-to storage is actually defined as having the const attribute that would be a mistake.
henry@utzoo.uucp (Henry Spencer) (02/25/90)
In article <1214@watserv1.waterloo.edu> semicon@watsci.UUCP (Robert Adsett) writes: >...If I either add const to the prototype or remove it from >the argument to junk it compiles without error. Is there some reason >that 'const double *b' should be treated differently from 'const >struct qwert *c'? ... I'd diagnose this as a buggy or obsolete compiler. The semantics of const in ANSI C were a moving target for quite some time. -- "The N in NFS stands for Not, | Henry Spencer at U of Toronto Zoology or Need, or perhaps Nightmare"| uunet!attcan!utzoo!henry henry@zoo.toronto.edu
henry@utzoo.uucp (Henry Spencer) (02/25/90)
In article <90054.232325CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes: >... you simply can't pass a structure by value. Passing (and returning) structures by value has been a feature of C for over a decade. -- "The N in NFS stands for Not, | Henry Spencer at U of Toronto Zoology or Need, or perhaps Nightmare"| uunet!attcan!utzoo!henry henry@zoo.toronto.edu
darcy@druid.uucp (D'Arcy J.M. Cain) (02/25/90)
In article <90054.232325CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes: > >The double is passed by value; so dereferencing it works fine. But the >struct is passed by reference (as are *all* structures in C!). In reality, >you need to pass a "struct qwert *" to the function. Normally, the compiler >takes the reference automatically, but you are trying to do this in reverse. >Thus, it does not work; you simply can't pass a structure by value. > Bzzzzzzt!! That may be true for K&R1 but both K&R2 and ANSI both allow passing structures by value. Granted this may not be something that you want to do too often but it is permissible. Even K&R1 hinted that it would one day be allowed. You can even do something like the following: struct qwert foo; struct qwert bar(struct qwert x); ... foo = bar(foo); Of course sending the address would be more efficient in the above example. -- D'Arcy J.M. Cain (darcy@druid) | Thank goodness we don't get all D'Arcy Cain Consulting | the government we pay for. West Hill, Ontario, Canada | (416) 281-6094 |
jseidman@jarthur.Claremont.EDU (James Seidman) (02/26/90)
In article <414@charyb.COM> will@charyb.UUCP (Will Crowder) writes: >Actually, I'm somewhat surprised that Turbo C didn't just throw out the >"const" in: > > void asdf(const struct qwert a); > >I wouldn't think "const" would mean much for a non-pointer parameter passed >by value. I would think that "const" in this context would mean pretty much the same thing as it would in a normal variable declaration. That is, that the function asdf() won't change the parameter a locally. Granted, about the only use for this is to generate warnings if you accidentally do assign a new value to a (like in "if (a = 2) then...") and to improve readibility of code. Of course, this doesn't explain why the compiler complained, but it should not just throw away the "const" qualifier. -- ------------------------------------------------------------------------------- Jim Seidman, Harvey Mudd College, Claremont, CA 91711. (714) 621-8000 x2026 DISCLAIMER: I don't even know if these are opinions, let alone those of anyone other than me.
efinley%ug.utah.edu@cs.utah.edu (Elliott Finley) (02/26/90)
(Charles Hannum) writes:
The double is passed by value; so dereferencing it works fine.
But the struct is passed by reference (as are *all* structures in
C!). In reality, you need to pass a "struct qwert *" to the
function. Normally, the compiler takes the reference
automatically, but you are trying to do this in reverse. Thus,
it does not work; you simply can't pass a structure by value.
Here is an excerpt from K&R2, chapter 6, page 127
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
The main change made by the ANSI standard is to define structure
assignment--structures may be copied and assigned to, passed to
functions, and returned by functions. This has been supported by most
compilers for many years, but the properties are now precisely
defined. Automatic structures and arrays may now also be initialized.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Chapter 6.2 page 129
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Let us investigate structures by writing some functions to
manipulate points and rectangles. There are at least three possible
approaches: pass components separately, pass an entire structure, or
pass a pointer to it. Each has its good points and bad points.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
So you can clearly see that the statement made above "But the
struct is passed by reference (as are *all* structures in C!)" is not true!
Elliot
P.S. It is ALOT more efficient to pass a pointer to a structure.