Type-casting void pointers?

H

hugo2

Obrhy/hugo July 12, 2004

Take a look at this memcpy() definition.
Is there a good reason the void pointer
args are cast to byte just to assign their
addresses to byte pointers?

/*from Steve Maguire's 'Writing Soild Code'*/

void *memcpy(void *pvTo,void *pvFrom,size_t size)
{
byte *pbTo = (byte *)pvTo;
byte *pbFrom = (byte *)pvFrom;
while(size-- >0)
*pbTo++ = *pbFrom++;

return (pvTo);
}

The addresses are all unsigned int. Why not
simply byte *pbTo = pvTo; to initialize?

hugo ---------
 
A

Alexei A. Frounze

hugo2 said:
Obrhy/hugo July 12, 2004

Take a look at this memcpy() definition.
Is there a good reason the void pointer
args are cast to byte just to assign their
addresses to byte pointers?

/*from Steve Maguire's 'Writing Soild Code'*/

void *memcpy(void *pvTo,void *pvFrom,size_t size)
{
byte *pbTo = (byte *)pvTo;
byte *pbFrom = (byte *)pvFrom;
while(size-- >0)
*pbTo++ = *pbFrom++;

return (pvTo);
}

The addresses are all unsigned int. Why not
simply byte *pbTo = pvTo; to initialize?

IMO there's no need in this if those are void*.
And unless someone's Clib implementation is broken, size_t is a nonnegative
type, hence no need to put size-->0, simply size would do.
I've seen ssize_t somewhere in linux recently, even in the single unix spec.
Stupid thing IMO. It limits the valid range by allowing signed values asking
for problems...

Alex
 
M

Michael Mair

hugo2 said:
Obrhy/hugo July 12, 2004

Take a look at this memcpy() definition.
Is there a good reason the void pointer
args are cast to byte just to assign their
addresses to byte pointers?

/*from Steve Maguire's 'Writing Soild Code'*/

Did you forget an 'e' or get wrong the order of 'i'
and 'l'? SCNR
void *memcpy(void *pvTo,void *pvFrom,size_t size)
{
byte *pbTo = (byte *)pvTo;
byte *pbFrom = (byte *)pvFrom;
while(size-- >0)
*pbTo++ = *pbFrom++;

return (pvTo);
}

The addresses are all unsigned int. Why not
simply byte *pbTo = pvTo; to initialize?

In the case of void*, the cast is completely unnecessary.
I do not know the definition of the type "byte" but if
it is anything other than a typedef for "unsigned char", I would
suggest that you have a look at the wisdom to be found in
c.l.c rather than believing this book: Unnecessary casts
are a Bad Thing.

Cheers
Michael
 
D

Default User

hugo2 said:
Obrhy/hugo July 12, 2004

Take a look at this memcpy() definition.
Is there a good reason the void pointer
args are cast to byte just to assign their
addresses to byte pointers?

/*from Steve Maguire's 'Writing Soild Code'*/

void *memcpy(void *pvTo,void *pvFrom,size_t size)
{
byte *pbTo = (byte *)pvTo;
byte *pbFrom = (byte *)pvFrom;
while(size-- >0)
*pbTo++ = *pbFrom++;

return (pvTo);
}

The addresses are all unsigned int. Why not
simply byte *pbTo = pvTo; to initialize?


You are correct, the cast is not required in C. It would be in C++, so
that could be reason for that usage. It's similar to the casts for the
returns from the *alloc() family, not necessary but a LOT of code
examples out there do it anyway. I don't know anything about that book
you mention.




Brian
 
P

pete

hugo2 said:
Obrhy/hugo July 12, 2004

Take a look at this memcpy() definition.
Is there a good reason the void pointer
args are cast to byte just to assign their
addresses to byte pointers?
No.

/*from Steve Maguire's 'Writing Soild Code'*/

void *memcpy(void *pvTo,void *pvFrom,size_t size)
{
byte *pbTo = (byte *)pvTo;
byte *pbFrom = (byte *)pvFrom;
while(size-- >0)
*pbTo++ = *pbFrom++;

return (pvTo);
}

The addresses are all unsigned int.

What do you mean by that?
I don't see any code about "unsigned int".
"byte" either means "unsigned char" or the definition is wrong.
memcpy works on objects of all types.
Why not simply byte *pbTo = pvTo; to initialize?

Sure.
Also, the parameter types are wrong.
There should be a const qualifier in front of void *pvFrom,
and if it were there,
then who knows if Steve Maguire's intention
would be to cast the qualifier away or not?

I'm also not to crazy about the "byte" typedef or macro,
which ever it is.
 
K

Keith Thompson

hugo2 said:
The addresses are all unsigned int.
[snip]

Are you assuming that an address is represented as an unsigned int?
If so, that assumption is neither correct nor necessary. An address
is an address. Addresses/pointers can be converted to and from
integer types, but there are very few guarantees about the results.
And I've worked on machines where unsigned int is 32 bits and pointers
are 64 bits.

A conforming implementation could implement pointers as fixed-length
strings that give instructions, in English, for retrieving the
referenced object ("1st memory board, 3rd chip on the left, 7th word").
 
H

hugo2

Alexei said:
IMO there's no need in this if those are void*.
And unless someone's Clib implementation is broken, size_t is a nonnegative
type, hence no need to put size-->0, simply size would do.
I've seen ssize_t somewhere in linux recently, even in the single unix spec.
Stupid thing IMO. It limits the valid range by allowing signed values asking
for problems...

Alex
From hugo, July 16, 2005
Mr Alex, I think, took a space out of size-- >0
After first seeing it, I read "subtract 1 from size
and compare to 0, greater? do while... subtract 1
form size, compare to 0, and so on.

hugo-------
 
A

Alexei A. Frounze

....
Mr Alex, I think, took a space out of size-- >0
After first seeing it, I read "subtract 1 from size
and compare to 0, greater? do while... subtract 1
form size, compare to 0, and so on.

Yeah, I obviously meant this:
....
while(size--)
....
No need to check for the sign, just for 0. If we code way too solid (I'd
rather say overdefensively), we may end up in a clinic for psychos with a
diagnosis of multiple phobias :)

Alex
 
S

Stephan Hoffmann

Default said:
You are correct, the cast is not required in C. It would be in C++, so
that could be reason for that usage. It's similar to the casts for the
returns from the *alloc() family, not necessary but a LOT of code
examples out there do it anyway. I don't know anything about that book
you mention.

I think some compilers give a warning without the explicit cast.
Maybe the author wanted to write 'warning-free' code.

Stephan
 
C

CBFalconer

Stephan said:
I think some compilers give a warning without the explicit cast.
Maybe the author wanted to write 'warning-free' code.

If a warning appears it is because it is needed. Useless casts
serve only to preserve programming errors.
 
R

Richard Heathfield

If so, it's a lousy warning.

Writing bad code to avoid lousy warnings is a lousy idea. Sometimes, we do
it anyway, I know - but we should do so in the full knowledge that it's a
lousy idea, and we should feel guilty for weeks afterwards. Or even months.

If a warning appears it is because it is needed.

Would that that were the case! Some compilers diagnose perfectly good,
idiomatic, ordinary C code. Grrr.

Useless casts serve only to preserve programming errors.

Well, no; they certainly do preserve programming errors, but they can /also/
serve to cut down the diagnostics count.
 
C

Chris Croughton

If so, it's a lousy warning.

Yup. There are some lousy compilers out there.
Writing bad code to avoid lousy warnings is a lousy idea. Sometimes, we do
it anyway, I know - but we should do so in the full knowledge that it's a
lousy idea, and we should feel guilty for weeks afterwards. Or even months.

I do, but it's a job requirement (specifically, we don't get to choose
the compiler, that's determined by what the customer is using, and
delivering code with hundreds of warnings is not good for business).
Would that that were the case! Some compilers diagnose perfectly good,
idiomatic, ordinary C code. Grrr.

Indeed. while(1) is a common case, as is assigning an integer value to
a smaller type ("char ch = (val % 10) + '0';"). The big problem is that
such warnings, while they may indicate mistakes, more often obscure the
real diagnostics (on some compilers I've had so many warnings about
perfectly good code that I couldn't even find the fatal errors).
Well, no; they certainly do preserve programming errors, but they can /also/
serve to cut down the diagnostics count.

The cast, where it is obvious, can also be used as documentation: "Yes,
I really do mean to put an int into a characters variable dammit!".

In particular, I've never come across any case in professional
programming where casting malloc() (or other void pointer) actually
masked a failure to declare it or include the relevant header file,
whereas I have come across cases where:

pointer = (my_type*) malloc(sizeof(my_type));

correctly pointed out that the type of the pointer was not the same as
expected, whereas just assigning the void pointer wouldn't have created
any diagnostic at all.

Chris C
 
K

Keith Thompson

Chris Croughton said:
In particular, I've never come across any case in professional
programming where casting malloc() (or other void pointer) actually
masked a failure to declare it or include the relevant header file,
whereas I have come across cases where:

pointer = (my_type*) malloc(sizeof(my_type));

correctly pointed out that the type of the pointer was not the same as
expected, whereas just assigning the void pointer wouldn't have created
any diagnostic at all.

Which is why the recommended idiom is

pointer = malloc(sizeof *pointer);
 
P

pete

Chris Croughton wrote:
In particular, I've never come across any case in professional
programming where casting malloc() (or other void pointer) actually
masked a failure to declare it or include the relevant header file,
whereas I have come across cases where:

pointer = (my_type*) malloc(sizeof(my_type));

correctly pointed out that the type of the pointer was not the same as
expected,
whereas just assigning the void pointer wouldn't have created
any diagnostic at all.

If pointer points to type mytype, or even if not,
then the clc idiomatic way:
pointer = malloc(sizeof *pointer);
seems best to me.

If pointer points to type void,
then my preference is to locate in the code,
an object identifier with the appropriate type and use that.

tail -> data = malloc(sizeof object);

*(struct oobject *)tail -> data = object;

For sizeof based arguments in a malloc call,
my preference is always sizeof object_identifier, never sizeof(type).
 
T

Tim Woodall

In particular, I've never come across any case in professional
programming where casting malloc() (or other void pointer) actually
masked a failure to declare it or include the relevant header file,
whereas I have come across cases where:
In my last job when we first ported to some of the 64 bit architectures
we found a few dozen places like this where the cast of malloc had
masked the warning (and the code didn't work with 32bit ints, 64 bit
pointers)


Tim.
 
K

Keith Thompson

Keith Thompson said:
Which is why the recommended idiom is

pointer = malloc(sizeof *pointer);

Following up to myself ...

On the other hand, the cast could conceivably reveal the error that
"pointer" should be of type my_type, but is actually of type
some_other_type. This assumes that the correct type is more obvious
in the context of the malloc() call than at the point of declaration.
I still think it's more likely to mask an error than to reveal one.
 
A

Alexei A. Frounze

Wasn't that Maxwell? :) And obviosly, someone had to throw a few particles
in to start things rolling.
Alex
P.S. there had been a mathematician before Maxwell to come up with those
equations.
 
O

Old Wolf

Chris said:
I do, but it's a job requirement (specifically, we don't get to choose
the compiler, that's determined by what the customer is using, and
delivering code with hundreds of warnings is not good for business).

Out of interest, which compilers do warn about correct usage of
malloc?

The worst I've seen is a warning when you cast something to
the same type it already was. For example:

isprint( (unsigned char)ch );

If you compile with plain char unsigned, it will warn about this
cast.

It gets really annoying in macros, where you often put in casts
because the macro could really be called with any integral type,
and then this compiler would warn when you use the one type that
matches the cast.

It was possible to turn off this warning, but not without also
turning off important warnings. :X
In particular, I've never come across any case in professional
programming where casting malloc() (or other void pointer) actually
masked a failure to declare it or include the relevant header file,

How many platforms have you programmed on where int, size_t,
and void* are not interchangeable, and the compiler does not
have special recognition of standard library functions?
whereas I have come across cases where:

pointer = (my_type*) malloc(sizeof(my_type));

correctly pointed out that the type of the pointer was not the
same as expected, whereas just assigning the void pointer wouldn't
have created any diagnostic at all.

There would not have been any diagnostic in either case, if the
parameter to malloc were wrong, ie.

pointer = (correct_type*) malloc(sizeof(my_type));

So this is a bit of a Pascal's wager.

Note that this problem can be eschewed with:

malloc(sizeof *ptr);
 
K

Keith Thompson

Old Wolf said:
The worst I've seen is a warning when you cast something to
the same type it already was. For example:

isprint( (unsigned char)ch );

If you compile with plain char unsigned, it will warn about this
cast.

Even worse, plain char and unsigned char are distinct types, even if
plain char happens to be unsigned. If the compiler complains that the
cast is unnecessary, I can see the point. If it complains that the
argument is of the same type specified in the cast, it's just wrong.
 

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,166
Messages
2,570,907
Members
47,448
Latest member
DeanaQ4445

Latest Threads

Top