Thread View: comp.lang.c.moderated
2 messages
2 total messages
Started by Chris Torek
Mon, 08 Apr 1996 16:20
Re: (double **) void **
Author: Chris Torek
Date: Mon, 08 Apr 1996 16:20
Date: Mon, 08 Apr 1996 16:20
66 lines
3185 bytes
3185 bytes
(I started this out as mail but decided to send it to the newsgroup
as well.)
In article <4k60po$aic@solutions.solon.com> thomas@eel.rdc.toshiba.co.jp
writes:
>The function is listed below, and I'd like to know if it is legal.
`Legal' is not a well-defined term. The code is not strictly
conformant (depends on both implementation-defined and undefined
behaviour). It will probably *work* on most systems.
> m = (void **) calloc(len_d1, sizeof(void *)); /* Is (void **) a */
> if(!m) nrerror("allocation failure 1 in matrix()"); /* valid data type?*/
Yes, `void **' is a valid data type. Here calloc() allocates len_d1
objects of type `void *' (or returns NULL).
The cast is redundant, since `calloc' is declared in <stdlib.h> and
has type `void *'.
Using calloc() instead of malloc() offers no real advantage (although
some people argue that you might be able to allocate more memory
via calloc() than via malloc(), since malloc requires that you
multiply your two size_t's yourself, which might overflow). The
calloc() function sets the newly-allocated memory to all-bits-zero,
which is not a useful pointer value.
> for(len_d1--; 0 <= len_d1; len_d1--) {
> m[len_d1] = (void *) calloc(len_d2, tsize); ...
This cast is similarly redundant. Again, calloc() buys little in
this particular case, since all-bits-zero is not a useful `double'
value; of course, matrix() does not really know that the memory
will be used to hold doubles.
> double **m;
> m = (double **) matrix(10, 10, sizeof(double));
The effect of this conversion is undefined. The matrix() function
has returned a pointer of type `void **', pointing to the first of
10 `void *'s. You can use these `void *'s via, e.g.,
void **m;
double *p;
m = matrix(10, 10, sizeof(double));
p = m[i]; /* 0 <= i < 10; causes a conversion */
... now can use p[j], where 0 <= j < 10 ...
Note that the conversion from `void *' to `double *' is well-defined,
since each of the `void *'s in m[i] came from a successful calloc();
p[j] is likewise well-defined, because it has been converted properly.
If you simply convert the `void **' to a `double **', the effect
is implementation-defined. The resulting `double **' value, whatever
it is, does not really point to `double *'s, and the effect of
accessing any of them is undefined.
The key to understanding this is that the cast performs a conversion,
and the conversion must be done from `void *' to whatever-the-correct-
type-is. It can be deferred (as with the `p = m[i]' line), but it
must eventually be done, and it must be done on the `void *' that
calloc() (or malloc()) returned.
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA Domain: torek@bsdi.com +1 510 234 3167
Re: (double **) void **
Author: Chris Torek
Date: Tue, 09 Apr 1996 03:46
Date: Tue, 09 Apr 1996 03:46
18 lines
1137 bytes
1137 bytes
I hate to have to follow up to my own article, but... In article <4kbebt$eiv@solutions.solon.com> I wrote: >> double **m = (double **) [expression of type `void **'] >The effect of this conversion is undefined. ... the effect >is implementation-defined. Clearly the effect cannot be both undefined and implementation- defined! I think (from 3.3.4) that `undefined' is correct here (since there is no known relationship between the alignment constraints for `void **' and `double **'). In any case, however, portable code must not depend on the result. -- In-Real-Life: Chris Torek, Berkeley Software Design Inc El Cerrito, CA Domain: torek@bsdi.com +1 510 234 3167
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads