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 |
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.
walter@hpclwjm.HP.COM (Walter Murray) (02/27/90)
Robert Adsett: > #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. Doug Gwyn: > 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. But in the posted example, the argument and parameter are structures, not pointers. It seems to me that the code is legal. Walter Murray ----------
gwyn@smoke.BRL.MIL (Doug Gwyn) (02/28/90)
In article <12570046@hpclwjm.HP.COM> walter@hpclwjm.HP.COM (Walter Murray) writes: >But in the posted example, the argument and parameter are structures, >not pointers. It seems to me that the code is legal. Thanks for posting the original example, which I had misremembered as passing a pointer, not the actual struct. Of course you're right that a qualified struct can be passed to a function expecting an unqualified struct, because the argument is assignment-compatible (meaning: 3.3.16.1 Constraints are met) with the parameter type, once the qualifier is stripped as per 3.2.2.1, as footnote 48 in the December 1988 draft reminds us. It's easy to see how an implementor could miss that, by not taking literally the requirement that argument passing be as if by simple assignment.