C portability gotcha, example
Ken Latham
latham at bsdpkh.UUCP
Thu Oct 31 05:50:25 AEST 1985
Concerning the following 'test' program ....
which functions on some but not all machines.
> struct node { int op; struct node *left, *right; double val; }
> *lp, *rp, *p, *makenode();
> double value; /* constant value from lex */
> ...
> p = makenode( 'x', lp, rp ); /* create multiply node */
> ...
> p = makenode( 'k', value ); /* create real constant node */
> ...
> struct node *makenode( op, arga, argb )
> int op; struct node *arga, *argb;
> { extern char *malloc();
> ...
> case 'k': /* real constant */
> new->val = *(double *)&arga; /* XXX */
> break;
> }
> return new;
> }
>
> The code failed at point "XXX". The exercise for the
> student is to figure out precisely WHY it fails ......
>
I'm not a student ( by the formal def. ), but I LOVE puzzles!!!
The answer becomes rather obvious after a little thought...
It is hidden in what can be refered to as "an implied sizeof" that is
necessary for the passage of variables from one function to another.
The size of (node *) is the same as the size of (double) on SOME machines
but not others ( I'm fairly sure it is not on MOST ).
On those machines where the size differs , the passage of the double into
a space too small to contain it usually causes an error on reference to it.
( Why? because stack space is given for an 'int' and 2 'node *'
when a double exceeds the space of two pointers there may
be problems depending on what is happens to the stack .... )
(NOTE: the 'int' space is given and used in both cases )
The reference to it copies from a space the size of double on the stack
starting at the beginning of a space too small to contain it, the excess
space used by the double may be corrupted ( especially if the reference is
late in the function ).
Here the call to malloc corrupts the overage used by the double since
it utilizes the stack ( as all good little functions do. )
> .... A second exercise for the student
> is to figure out how to fix this code ......
>
the fix.....
pass a pointer to the double instead of the double itself.
i.e.
p = makenode ('k', &value );
... and reference it as such ....
struct node *makenode( op, arga, argb )
int op; struct node *arga, *argb;
{ extern char *malloc();
...
case 'k': /* real constant */
new->val = (double *)arga; /* XXXXXXXXXXX */
break;
...
}
There's a chance that there may be other problems I am not aware
of but this seems to be at least one case where "sometimes it works and
somtimes it doesn't."
Concerning those who have a great deal of experience:
" There are those who have many experiences...
and those who have few experiences many times."
-- I'm not sure who --
-- but not me --
_______________________________________________________________________________
| | |
| Ken Latham | uucp: ihnp4!bsdpkh!latham |
| AT&T-IS | uucp: {ihnp4!decvax,peora}!ucf-cs!latham |
| Orlando , FL | arpa: latham.ucf-cs at csnet-relay |
| USA | csnet:latham at ucf |
|_____________________________|_______________________________________________|
--
Concerning those who have a great deal of experience:
" There are those who have many experiences...
and those who have one experience many times."
_______________________________________________________________________________
| | |
| Ken Latham | uucp: ihnp4!bsdpkh!latham |
| AT&T-IS | uucp: {ihnp4!decvax,peora}!ucf-cs!latham |
| Orlando , FL | arpa: latham.ucf-cs at csnet-relay |
| USA | csnet:latham at ucf |
|_____________________________|_______________________________________________|
More information about the Comp.lang.c
mailing list