[comp.lang.c] const and struct pointers

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.