If I write stack routines and want to push and pop pointers of any type, is
it portable/safe to accept a void * as the type passed to these functions?
void push( void *p )
void *pop()
More importantly, when creating the array used to store these pointers, how
would one allocate such an array? Is there any difference between these two
examples and are they portable/safe?
arry = malloc( sizeof( char * ) * SIZE )
arry = malloc( sizeof( int * ) * SIZE )
In general I would like any feedback on style or whatever. Below is my
sample proggie.
Thanks,
Mike
--
1 // t0.c
2
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 #define SIZE 10
7
8 char **arry;
9 int sp = 0;
10
11 char *acharptr = "some text";
12
13 void
14 push( void *ptr ) {
15 arry[sp++] = ptr;
16 }
17
18 void*
19 pop() {
20 return arry[--sp];
21 }
22
23 int
24 main( int arc, char *argv[] ) {
25 arry = malloc( sizeof( char * ) * SIZE );
26 push( acharptr );
27 printf( "pushing: %s\n", acharptr );
28 printf( "popping: %s\n", (char *)pop() );
29 return 0;
30 }
[miallen@angus c]$ t0
pushing: some text
popping: some text
> If I write stack routines and want to push and pop pointers of any type, is
> it portable/safe to accept a void * as the type passed to these functions?
Sure.
> void push( void *p )
> void *pop()
>
> More importantly, when creating the array used to store these pointers, how
> would one allocate such an array?
void **array = malloc (sizeof *array * count);
> Is there any difference between these two
> examples and are they portable/safe?
>
> arry = malloc( sizeof( char * ) * SIZE )
> arry = malloc( sizeof( int * ) * SIZE )
The first allocates memory for an array of character pointers,
the latter for an array of integer pointers.
> 1 // t0.c
// is a C99-style comment, but there aren't any C99 compilers yet.
> 2
> 3 #include <stdio.h>
> 4 #include <stdlib.h>
> 5
> 6 #define SIZE 10
> 7
> 8 char **arry;
Why not void **?
> 9 int sp = 0;
> 10
> 11 char *acharptr = "some text";
> 12
> 13 void
> 14 push( void *ptr ) {
> 15 arry[sp++] = ptr;
I'd include an assertion to check for stack overflow.
> 16 }
> 17
> 18 void*
> 19 pop() {
> 20 return arry[--sp];
I'd include an assertion to check for stack underflow.
> 21 }
> 22
> 23 int
> 24 main( int arc, char *argv[] ) {
You know you don't have to declare those arguments if you're not
going to use them.
> 25 arry = malloc( sizeof( char * ) * SIZE );
> 26 push( acharptr );
> 27 printf( "pushing: %s\n", acharptr );
> 28 printf( "popping: %s\n", (char *)pop() );
> 29 return 0;
> 30 }
--
"Give me a couple of years and a large research grant,
and I'll give you a receipt." --Richard Heathfield
as long as your only pushing and popping pointers to objects.
> 1 // t0.c
> 2
> 3 #include <stdio.h>
> 4 #include <stdlib.h>
> 5
> 6 #define SIZE 10
> 7
> 8 char **arry;
since you're dealing with pointers to void, why not make this void **?
> 9 int sp = 0;
> 10
> 11 char *acharptr = "some text";
> 12
> 13 void
> 14 push( void *ptr ) {
> 15 arry[sp++] = ptr;
> 16 }
> 17
> 18 void*
> 19 pop() {
> 20 return arry[--sp];
> 21 }
> 22
> 23 int
> 24 main( int arc, char *argv[] ) {
> 25 arry = malloc( sizeof( char * ) * SIZE );
arry = malloc(sizeof *arry * SIZE);
is the generally preferred style.
> 26 push( acharptr );
> 27 printf( "pushing: %s\n", acharptr );
> 28 printf( "popping: %s\n", (char *)pop() );
you don't need the cast here.
> 29 return 0;
> 30 }
otherwise your program looks very good.
--
/"\ m i k e b u r r e l l
\ / ASCII RIBBON CAMPAIGN mik...@home.com
X AGAINST HTML MAIL,
/ \ AND NEWS TOO, dammit finger mik...@mikpos.dyndns.org for GPG key
> > 18 void*
> > 19 pop() {
> > 20 return arry[--sp];
> > 21 }
[...]
> > 28 printf( "popping: %s\n", (char *)pop() );
>
> you don't need the cast here.
We had a long discussion of a similar topic around here (and
c.s.c) earlier: whether char * was okay as an argument
corresponding to %p. I don't recall that there was a definite
conclusion. As a result, I think it's safest to keep the cast.
[major snippage]
--
"I ran it on my DeathStation 9000 and demons flew out of my nose." --Kaz
> We had a long discussion of a similar topic around here (and
> c.s.c) earlier: whether char * was okay as an argument
> corresponding to %p. I don't recall that there was a definite
> conclusion. As a result, I think it's safest to keep the cast.
good to keep in mind :)
> mike burrell <mik...@home.com> writes:
>
> > > 18 void*
> > > 19 pop() {
> > > 20 return arry[--sp];
> > > 21 }
> [...]
> > > 28 printf( "popping: %s\n", (char *)pop() );
> >
> > you don't need the cast here.
>
> We had a long discussion of a similar topic around here (and
> c.s.c) earlier: whether char * was okay as an argument
> corresponding to %p. I don't recall that there was a definite
> conclusion. As a result, I think it's safest to keep the cast.
>
> [major snippage]
Actually James Kuyper did a pretty good job of settling this on
comp.std.c. Here's the relevant quote from section 6.2.5 of the final
C99 standard:
[#26] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character
type.39)
Footnote 39 adds:
39)The same representation and alignment requirements are
meant to imply interchangeability as arguments to
functions, return values from functions, and members of
unions.
Jack Klein
--
Home: http://jackklein.home.att.net
>mike burrell <mik...@home.com> writes:
>
>> > 18 void*
>> > 19 pop() {
>> > 20 return arry[--sp];
>> > 21 }
>[...]
>> > 28 printf( "popping: %s\n", (char *)pop() );
>>
>> you don't need the cast here.
>
>We had a long discussion of a similar topic around here (and
>c.s.c) earlier: whether char * was okay as an argument
>corresponding to %p. I don't recall that there was a definite
>conclusion. As a result, I think it's safest to keep the cast.
There are two other reasons for keeping the cast:
1. Readability. It's weird to see a void * passed as argument to %s.
The cast says to the reader: "this is really a char pointer, stored in
in a void pointer".
2. gcc -Wall will complain about the argument mismatch.
Dan
--
Dan Pop
CERN, IT Division
Email: Dan...@cern.ch
Mail: CERN - IT, Bat. 31 1-014, CH-1211 Geneve 23, Switzerland
Mine doesn't complain.
GCC VERSION:
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.7.2.3/specs
gcc version 2.7.2.3
USAGE:
[miallen@angus c]$ gcc -Wall -g stack.o -o t2 t2.c
My recollection is that comp.std.c never really arrived at
consensus on this. I think I was the first one to cite that
footnote, perhaps before the discussion moved from comp.lang.c to
comp.std.c, but the footnote is non-normative, and I don't
remember any agreement on whether there's any language in the
actual standard which says that the same representation and
alignment requirements really *do* mean interchangeability.
--
Morris M. Keesan -- mke...@lucent.com
Lucent Technologies Software Products Group
As it happens, I tried with 2.7.2.3, too, after removing the cast from
your program:
ues5:~/tmp 92> gcc -Wall test.c
test.c: In function `main':
test.c:28: warning: char format, void arg (arg 2)
ues5:~/tmp 93> gcc -v
Reading specs from /usr/local/lib/gcc-lib/alpha-dec-osf3.2/2.7.2.3/specs
gcc version 2.7.2.3