void * pointer convert problem.

E

Eric J.Hu

Hi,

I have following code, want do pointer convert. It always complain:

vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer
vcnvt.c:20: request for member `key' in something not a structure or union
---------------------------
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
u_long key;
u_long transCmdAdd;
u_long transCmdMod;
u_long transCmdSub;
u_long transCount;
} counting_bin_t, *counting_bin_p;

int main()
{
void * vbPtr;
counting_bin_t cBin[9];
cBin[0].key = 9;

vbPtr = cBin;
printf("key is %d\n", vbPtr->key);
}



Thanks,
Eric
 
C

Christopher Benson-Manica

Eric J.Hu said:
vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer

Pretty self-explanatory. You can't derefence void pointers. You can,
however, cast them back to their real type and then dereference them.
int main()
{
void * vbPtr;
counting_bin_t cBin[9];
cBin[0].key = 9;
vbPtr = cBin;
printf("key is %d\n", vbPtr->key);

/* Like so */

printf( "key is %d\n", ((counting_bin_t*)vbPtr)->key );
 
N

nelu

Eric said:
Hi,

I have following code, want do pointer convert. It always complain:

vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer
vcnvt.c:20: request for member `key' in something not a structure or union
---------------------------
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
u_long key;
u_long transCmdAdd;
u_long transCmdMod;
u_long transCmdSub;
u_long transCount;
} counting_bin_t, *counting_bin_p;

int main()

use int main(void)
{
void * vbPtr;
counting_bin_t cBin[9];
cBin[0].key = 9;

vbPtr = cBin;
you tell vbPtr to point to cBin
printf("key is %d\n", vbPtr->key);
vbPtr is a void pointer so it has no idea who key is. The fact that you
do: vbPtr=cBin doesn't change the type of vbPtr from void * to
counting_bin_t *. You could cast (counting_bin_t *)vbPtr to obtain what
you need. Even with the cast you should be aware that
(counting_bin_t*)vbPtr->key may not be the same as
((counting_bin_t*)vbPtr)->key.
 
F

Flash Gordon

Eric said:
Hi,

I have following code, want do pointer convert. It always complain:

English may not be your first language, but that is too poor for me to
know what you actualy want to do.
vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer

That's simple. You are not allowed to use the * operator on a void*
pointer. The reason being, void* is a generic pointer type so how is the
compiler meant to know what sort of value you expect to get? Does it
point to an int, a char or what?

Note that:
x->y means the same as (*x).y
I.e., it means dereference x and then access field y within it.
vcnvt.c:20: request for member `key' in something not a structure or union

That's simple as well, dereferencing a void* pointer does not give you
something with a struture type (since it is invalid), so obviously
trying to access a field named key within it is not possible.

Your example does not use anything from stdlib.h so why include it?
typedef struct
{
u_long key;
u_long transCmdAdd;
u_long transCmdMod;
u_long transCmdSub;
u_long transCount;
} counting_bin_t, *counting_bin_p;

Many people think it is better not to hide either pointers or structs
behind typedefs.
int main()

If you are not using parameters, it is better to be explicit as a matter
of habit.

int main(void)
{
void * vbPtr;
counting_bin_t cBin[9];
cBin[0].key = 9;

vbPtr = cBin;

This is perfectly valid, but in your example it is pointless so I can't
really see what you want to know about.
printf("key is %d\n", vbPtr->key);

The above line is the one with the problem, since you are trying to
dereference a void* pointer (which is illegal) and then access a field
within the resultant value (which is again obviously impossible).

The whole point of void* pointers is they can point to anything.

Main returns an int, wouldn't it be better to actually do this? (C99
allows falling of the end of main to act as if 0 was returned, but most
compilers are not C99 compilers).

return 0;
 
E

Eric J.Hu

Christopher,

Thansk for your quick answer.
If need do casting back, that's not what I want. Following is my program. I
just want to ignore which structure it refer to. Please see line 342.

314 u_long hbHash( upm_histogram_bin_p hPtr, u_long key,
histogram_bin_type_tag hbt)
315 {
316 u_long i;
317 void* bPtr;
323 if( hbt == PROC_TIMING_BIN)
324 {
325 bPtr = (proc_timing_bin_p)(&hPtr->ptBin[0]);
326 }
327 else if(hbt == EXEC_TIMING_BIN)
328 {
329 bPtr = (exec_timing_bin_p)(&hPtr->etBin[0]);
330 }
340 for (i =0 ; i< MAX_HIST_BIN_SIZE; i++)
341 {
342 if(key < bPtr->key)
343 return i;
344 else
345 continue;
346 bPtr ++;
347 }
351 return INVALID;
352 }

Thanks,
Eric
------------------------------------------
Christopher Benson-Manica said:
Eric J.Hu said:
vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer

Pretty self-explanatory. You can't derefence void pointers. You can,
however, cast them back to their real type and then dereference them.
int main()
{
void * vbPtr;
counting_bin_t cBin[9];
cBin[0].key = 9;
vbPtr = cBin;
printf("key is %d\n", vbPtr->key);

/* Like so */

printf( "key is %d\n", ((counting_bin_t*)vbPtr)->key );
 
D

David Resnick

Eric said:
Christopher,

Thansk for your quick answer.
If need do casting back, that's not what I want. Following is my program. I
just want to ignore which structure it refer to. Please see line 342.

314 u_long hbHash( upm_histogram_bin_p hPtr, u_long key,
histogram_bin_type_tag hbt)
315 {
316 u_long i;
317 void* bPtr;
323 if( hbt == PROC_TIMING_BIN)
324 {
325 bPtr = (proc_timing_bin_p)(&hPtr->ptBin[0]);
326 }
327 else if(hbt == EXEC_TIMING_BIN)
328 {
329 bPtr = (exec_timing_bin_p)(&hPtr->etBin[0]);
330 }
340 for (i =0 ; i< MAX_HIST_BIN_SIZE; i++)
341 {
342 if(key < bPtr->key)
343 return i;
344 else
345 continue;
346 bPtr ++;
347 }
351 return INVALID;
352 }

Thanks,
Eric

Hi Eric,

Conversations make more sense that way.
Folks here don't like top posting, please post after the thing being
replied to.
(above two lines flipped on purpose)

Anyway, I think you aren't clear on the issue with the way
you are trying to use void *.

You (or at least the compiler) can't know without casting
or assigning to something with a non-void type what object type a
pointer to void actually refers to. You are saying on line 342 that
bPtr, a pointer to void, is actually a pointer to some struct that has
a
key field. But the compiler has no way to know what type of structure
that may be (or in particular, what the offset of the key field is
within that
structure).

-David
 
T

tmp123

317 void* bPtr;
325 bPtr = (proc_timing_bin_p)(&hPtr->ptBin[0]);
329 bPtr = (exec_timing_bin_p)(&hPtr->etBin[0]);
342 if(key < bPtr->key)

Hi,

a) If the field key has the same offset in both strutures (proc and
exec), then you can use anyone:

if (key < (proc_timing_bin_p *)bPtr->key ) ...

b) If the offset is not the same, your request has no solution. The
most near is:

if (key < (hbt == PROC_TIMING_BIN)?(proc_timing_bin_p
*)bPtr->key:(exec_timing_bin_p *)bPtr->key ) ...

Kind regards.
 
C

Christopher Benson-Manica

Eric J.Hu said:
If need do casting back, that's not what I want.

Sadly, that's how it is. You can't dereference or increment (among
other things) a void pointer without casting it back to what it really
is.
Following is my program. I
just want to ignore which structure it refer to. Please see line 342.

I see it; not only is it wrong, but so is line 346, per above. It's
possible that you may be able to avoid the mundane solution with the
clever use of a macro; I haven't come up with the answer so far,
however.

(342 and 346 preserved for context; bPtr is declared as void *)
 
E

Eric J.Hu

tmp123 said:
317 void* bPtr;
325 bPtr = (proc_timing_bin_p)(&hPtr->ptBin[0]);
329 bPtr = (exec_timing_bin_p)(&hPtr->etBin[0]);
342 if(key < bPtr->key)

Hi,

a) If the field key has the same offset in both strutures (proc and
exec), then you can use anyone:

if (key < (proc_timing_bin_p *)bPtr->key ) ...

b) If the offset is not the same, your request has no solution. The
most near is:

if (key < (hbt == PROC_TIMING_BIN)?(proc_timing_bin_p
*)bPtr->key:(exec_timing_bin_p *)bPtr->key ) ...

Kind regards.

Yeah! They have same offset, so I can choose the first solution.


Thanks,
Eric
 
C

Christopher Benson-Manica

tmp123 said:
a) If the field key has the same offset in both strutures (proc and
exec), then you can use anyone:

I don't believe that's a portable assumption. The structures could
have different padding bits, so unless key is the first element (in
which case all is well, as structs can always be converted into a
pointer to their first element),
if (key < (proc_timing_bin_p *)bPtr->key ) ...

need not work. It still doesn't fix OP's other problem, in which he
attempted to increment the void pointer.
 
N

nelu

Christopher said:
I don't believe that's a portable assumption. The structures could
have different padding bits, so unless key is the first element (in
which case all is well, as structs can always be converted into a
pointer to their first element),

So if I have:

struct s1 {
int id;
char *name;
int year;
};

struct s2 {
int id;
char *name;
int year;
time_t tstamp;
};

....
void *p;
struct s2 b;
....
p=&b;
((struct s1 *)p)->year=2000;
....

the last assignment may not be portable?

I may be wrong, but I think GTK+ is doing something similar.
 
K

Keith Thompson

Eric J.Hu said:
I have following code, want do pointer convert. It always complain:

vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer
vcnvt.c:20: request for member `key' in something not a structure or union
---------------------------
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
u_long key;
u_long transCmdAdd;
u_long transCmdMod;
u_long transCmdSub;
u_long transCount;
} counting_bin_t, *counting_bin_p;
[snip]

In addition to the other comments you've gotten, what is "u_long"?
There is no such type declared in <stdio.h> or <stdlib.h> (or at least
there shouldn't be in a conforming implementation).

I'm guessing that u_long is a typedef for unsigned long, but why make
me guess? Just use "unsigned long" directly.
 
C

Christopher Benson-Manica

(IANALL; apply salt granules as appropriate.)
struct s1 {
int id;
char *name;
int year;
};
struct s2 {
int id;
char *name;
int year;
time_t tstamp;
};
...
void *p;
struct s2 b;
...
p=&b;
((struct s1 *)p)->year=2000;
...
the last assignment may not be portable?

That's my reading of 6.7.2.1 (12) of n869:

"Within a structure object, the non-bit-field members and the units in
which bit-fields reside have addresses that increase in the order in
which they are declared. A pointer to a structure object, suitably
converted, points to its initial member (or if that member is a bit-field,
then to the unit in which it resides), and vice versa. There may be
unnamed padding within a structure object, but not at its beginning."

There is nothing that I can see which forbids an implementation from
putting the year members at different offsets (due to the above
mentioned unnamed padding), making the code you provided nonportable.
Of course, non DS9K machines are unlikely to behave in such a
manner...
I may be wrong, but I think GTK+ is doing something similar.

....which is why GTK+ can probably get away with such code.
 
T

tmp123

Hi,

The problem of jump to next item in the array can have a similar
analisis:

a) Have both structures the same size? Then, use anyone:

bPtr=((exec_timing_bin_p *)bPtr)+1;

b) Have structures different sizes? Two workarounds (assertion:
sizeof(char)==1):

b1) Save the size, and use it after:

if( hbt == PROC_TIMING_BIN)
{
bPtr = (proc_timing_bin_p)(&hPtr->ptBin[0]);
bSize=sizeof(hPtr->ptBin[0]);
}
else if(hbt == EXEC_TIMING_BIN)
{
bPtr = (exec_timing_bin_p)(&hPtr->etBin[0]);
bSize=sizeof(hPtr->etBin[0]);
}

bPtr=((char *)bPtr)+bSize;

b2) Do not use a local, and get the size each time:

bPtr=((char *)bPtr)+(hbt == PROC_TIMING_BIN)?

sizeof(hPtr->ptBin[0]):

sizeof(hPtr->etBin[0]) );

Kind regards.
 
C

Christopher Benson-Manica

tmp123 said:
b) Have structures different sizes? Two workarounds (assertion:
sizeof(char)==1):

sizeof( char ) is 1, always, by definition.
b2) Do not use a local, and get the size each time:
bPtr=((char *)bPtr)+(hbt == PROC_TIMING_BIN)?
sizeof(hPtr->ptBin[0]):

sizeof(hPtr->etBin[0]) );

This strikes me as rather grotesque abuse of the ?= operator.

Additionally:

It is proper Usenet etiquette to include the relevant portions of the text
you are replying to. To do this using Google groups, please follow the
instructions below, penned by Keith Thompson:

If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
K

Keith Thompson

Christopher Benson-Manica said:
That's my reading of 6.7.2.1 (12) of n869:

"Within a structure object, the non-bit-field members and the units in
which bit-fields reside have addresses that increase in the order in
which they are declared. A pointer to a structure object, suitably
converted, points to its initial member (or if that member is a bit-field,
then to the unit in which it resides), and vice versa. There may be
unnamed padding within a structure object, but not at its beginning."

There is nothing that I can see which forbids an implementation from
putting the year members at different offsets (due to the above
mentioned unnamed padding), making the code you provided nonportable.
Of course, non DS9K machines are unlikely to behave in such a
manner...

But see also C99 6.5.2.3p5:

One special guarantee is made in order to simplify the use of
unions: if a union contains several structures that share a common
initial sequence (see below), and if the union object currently
contains one of these structures, it is permitted to inspect the
common initial part of any of them anywhere that a declaration of
the complete type of the union is visible. Two structures share a
_common initial sequence_ if corresponding members have compatible
types (and, for bit-fields, the same widths) for a sequence of one
or more initial members.

Strictly speaking, this guarantee applies only if the two structures
are members of the same union. If a compiler can prove to itself that
no such union exists in the program, it can theoretically use
different layouts for the common initial subsequences of two different
structure types. But it's difficult to imagine any non-DS9K
implementation going to the extra effort for no benefit I can think
of. The most straightforward way to comply with 6.5.2.3p5 is simply
to use layout rules that always guarantee the same layout for any
common initial subsequence.

If you're really concerned about conformance, you can declare (and not
bother to use) a union just to avoid the possibility, but I don't
think it's worth the effort.
 
M

Mark McIntyre

Christopher,

Thansk for your quick answer.
If need do casting back, that's not what I want. Following is my program. I
just want to ignore which structure it refer to.

Why? In C, you can't use the data inside the structure without knowing
what structure it is, since otherwise the compiler can't know what
members it has. Casting is how you do this in C.


Mark McIntyre
 
E

Eric J.Hu

Keith Thompson said:
Eric J.Hu said:
I have following code, want do pointer convert. It always complain:

vcnvt.c: In function `main':
vcnvt.c:20: warning: dereferencing `void *' pointer
vcnvt.c:20: request for member `key' in something not a structure or union
---------------------------
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
u_long key;
u_long transCmdAdd;
u_long transCmdMod;
u_long transCmdSub;
u_long transCount;
} counting_bin_t, *counting_bin_p;
[snip]

In addition to the other comments you've gotten, what is "u_long"?
There is no such type declared in <stdio.h> or <stdlib.h> (or at least
there shouldn't be in a conforming implementation).

I'm guessing that u_long is a typedef for unsigned long, but why make
me guess? Just use "unsigned long" directly.
You are right.

The u_long was defined in file:
/usr/include/linux/types.h
 
A

abdur_rab7

Eric said:
int main()
{
void * vbPtr;
counting_bin_t cBin[9];
cBin[0].key = 9;

vbPtr = cBin;
printf("key is %d\n", vbPtr->key);
}
vbPtr = cBin;
the declaration is legal as a pointer to any type can be assigned to a
void pointer without a cast, and vice versa.
printf("key is %d\n", vbPtr->key);

A void pointer is a pointer without a specified data type to describe
the object to which it points. In effect, it is a generic pointer. A
void pointer cannot be defrenced.

to print the value it should be type casted as
((counting_bin_t*)vbPtr)->key.

Best Regards,
Abdur
 
P

Peter Nilsson

... a pointer to any type can be assigned to a void pointer without a cast, ...

No, it's _almost_ any type. For instance, you generally can't assign a
function
pointer to a void pointer without a cast.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,172
Messages
2,570,934
Members
47,477
Latest member
ColumbusMa

Latest Threads

Top