[comp.lang.c] Suspicious pointer conversion warning in Turbo C 2.0

stever@Octopus.COM (Steve Resnick ) (07/26/90)

Hello Netlanders!

	Here's one for you...
 As far as I know, when I provide a prototype for a function which accepts
 a void pointer, the compiler should not bitch about type conversions between
 pointers. The code fragment below generates a warning message when I pass a
 pointer to a structure. The parameter bitched about is the second pointer.
 The first pointer in both cases is not complained about. The compiler
 generates the correct code, but I am wondering whether it should be
 bitching at me in the first place. Any ideas?

 Cheers!
 Steve


void AddLNode(void ** Hptr, void * Nptr);
void * DelLNode(void ** , void * );
main()
{
	Tlist *Head, *Walker;
	.
	.
	.
	AddLNode(&Head,Walker);	/* This statement generates a warning */
	for (Walker = Head; Walker != NULL ; Walker = Walker->Next)
		if (Walker->Idx == 0xDEAD)
			DelLNode(&Head,Walker); /* This statement generates a
						 warning */
}



-- 
----------------------------------------------------------------------------
{apple|pyramid|sun}!octopus!stever} Disclaimer: I speak only for me! 8-)
Flames, grammar errors, spelling errrors >/dev/nul
----------------------------------------------------------------------------

chris@mimsy.umd.edu (Chris Torek) (07/26/90)

In article <1990Jul25.230836.2442@Octopus.COM> stever@Octopus.COM
(Steve Resnick) writes:
>As far as I know, when I provide a prototype for a function which accepts
>a void pointer, the compiler should not bitch about type conversions between
>pointers. The code fragment below generates a warning message ....

The ANSI standard only says when diagnostics are required; it makes no
prohibitions about extra diagnostics.  In other words, compilers are free
to warn about anything they like (`foo.c, line 354: warning: code written
at 4 AM').

Of course, some warnings are rather less useful than others (although the
above might well be particularly good, actually).

>The parameter bitched about is the second pointer.
>The first pointer in both cases is not complained about.

[everything but the relevant bits trimmed:]
>void AddLNode(void ** Hptr, void * Nptr);
>	Tlist *Head, *Walker;
>	AddLNode(&Head,Walker);	/* This statement generates a warning */

Now this is exactly backwards: a good compiler should complain about
the first parameter, not the second.  Argument passing is semantically
equivalent to assignment, so the commented line is rather like writing:

	void **Hptr;
	void *Nptr;

	Hptr = &Head;
	Nptr = Walker;

The first assignment expands to

	<object, pointer to pointer to void, Hptr> =
		&<object, pointer to Tlist, Head>;

which becomes

	<object, void **, Hptr> = <value, Tlist **, &Head>;

which is an attempt to stuff a `Tlist **' into a `void **'.  The C
standard guarantees that any pointer type (e.g., Tlist **) must fit
into a `void *'; it makes no such guarantee about a `void **'.  In
other words, this need not work, and the compiler ought to complain.

The second assignment expands to

	<object, pointer to void, Nptr> =
		&<object, pointer to Tlist, Walker>;

which becomes

	<object, void *, Nptr> = <value, Tlist **, Walker>;

which (because Tlist** fits in void*) has to `work' (the compiler is
free to complain, but this should at least be an option, or customers
will turn away in droves).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

richardh@hpopd.HP.COM (Richard Hancock) (07/26/90)

I would expect a warning unless you cast the actual parameter to match the type of the formal parameter.

Don_A_Corbitt@cup.portal.com (07/27/90)

 > pointers. The code fragment below generates a warning message when I pass a
 > pointer to a structure. The parameter bitched about is the second pointer.

> void AddLNode(void ** Hptr, void * Nptr);
> void * DelLNode(void ** , void * );
> main()
> {
	> Tlist *Head, *Walker;
	> AddLNode(&Head,Walker);	/* This statement generates a warning */
> }
> {apple|pyramid|sun}!octopus!stever} Disclaimer: I speak only for me! 8-)
> Flames, grammar errors, spelling errrors >/dev/nul

1) The warnings you are getting are from the first parameter.  When I cast
it to AddLNode((void **)&Head, Walker); I don't get any warnings.  Chris Torek
gave you the correct answer.  What made you think the warnings were from the
second parameter?

2) Cross posting to alt.msdos.programmer, comp.lang.c, comp.os.msdos.programmer
usually means too many people are going to see the question and answer.  I'm
leaving the groups, but I suggest followups (if any) by mail.
---
Don_A_Corbitt@cup.portal.com      Not a spokesperson for CrystalGraphics, Inc.
Mail flames, post apologies.       Support short .signatures, three lines max.

karl@haddock.ima.isc.com (Karl Heuer) (07/27/90)

>> void AddLNode(void ** Hptr, void * Nptr);
>> Tlist *Head, *Walker;
>> AddLNode(&Head,Walker);	/* This statement generates a warning */
>
>The warnings you are getting are from the first parameter.  When I cast
>it to AddLNode((void **)&Head, Walker); I don't get any warnings.

It should be noted that, although it silences the warnings, the cast makes the
code incorrect.  It will fail on (existing) implementations where `Tlist *'
and `void *' do not have the same internal format.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
Followups to comp.lang.c only.

karl@haddock.ima.isc.com (Karl Heuer) (07/27/90)

>> void AddLNode(void ** Hptr, void * Nptr);
>> Tlist *Head, *Walker;
>> AddLNode(&Head,Walker);	/* This statement generates a warning */
>
>The warnings you are getting are from the first parameter.  When I cast
>it to AddLNode((void **)&Head, Walker); I don't get any warnings.

It should be noted that, although you can silence the warnings, the code
is incorrect with or without the cast.  It works on vaxlike architectures,
but will probably fail on (existing, not hypothetical) implementations where
`Tlist *' and `void *' do not have the same internal format.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
Followups to comp.lang.c only.

rommel@lan.informatik.tu-muenchen.dbp.de (Kai-Uwe Rommel) (07/27/90)

In article <1990Jul25.230836.2442@Octopus.COM> stever@octopus.COM (Steve Resnick ) writes:
> As far as I know, when I provide a prototype for a function which accepts
> a void pointer, the compiler should not bitch about type conversions between
> pointers. The code fragment below generates a warning message when I pass a
> pointer to a structure. The parameter bitched about is the second pointer.

>void AddLNode(void ** Hptr, void * Nptr);
>void * DelLNode(void ** , void * );

>	Tlist *Head, *Walker;
>	AddLNode(&Head,Walker);	/* This statement generates a warning */
>			DelLNode(&Head,Walker); /* This statement generates a

As you said, you can pass any pointer to a function declared with a
pointer to void as an argument. But you did not declare such a function.
"void *" and "void **" is not the same! The first is a pointer to void
but the second is a pointer to a pointer variable.

You should declare:
>void AddLNode(void * Hptr, void * Nptr);
>void * DelLNode(void * , void * );

Although you probably mean something what is called "call by reference"
you shoud declare it this way to avoid the warning. This declaration
does not prevent you to do the same in the AddLNode, DelLNode functions.
You will have to cast the arguments in these function to what you want
anyway.

Kai Uwe Rommel

--
/* Kai Uwe Rommel
 * Munich
 * rommel@lan.informatik.tu-muenchen.dbp.de
 */

stever@Octopus.COM (Steve Resnick ) (07/28/90)

In article <3629@tuminfo1.lan.informatik.tu-muenchen.dbp.de> rommel@lan.informatik.tu-muenchen.dbp.de (Kai-Uwe Rommel) writes:
>In article <1990Jul25.230836.2442@Octopus.COM> stever@octopus.COM (Steve Resnick ) writes:
>> As far as I know, when I provide a prototype for a function which accepts
>> a void pointer, the compiler should not bitch about type conversions between
>> pointers. The code fragment below generates a warning message when I pass a
>> pointer to a structure. The parameter bitched about is the second pointer.
>
>>void AddLNode(void ** Hptr, void * Nptr);
>>void * DelLNode(void ** , void * );
>
>>	Tlist *Head, *Walker;
>>	AddLNode(&Head,Walker);	/* This statement generates a warning */
>>			DelLNode(&Head,Walker); /* This statement generates a
>
>As you said, you can pass any pointer to a function declared with a
>pointer to void as an argument. But you did not declare such a function.
>"void *" and "void **" is not the same! The first is a pointer to void
>but the second is a pointer to a pointer variable.
>
>You should declare:
>>void AddLNode(void * Hptr, void * Nptr);
>>void * DelLNode(void * , void * );
>
>Although you probably mean something what is called "call by reference"
>you shoud declare it this way to avoid the warning. This declaration
>does not prevent you to do the same in the AddLNode, DelLNode functions.
>You will have to cast the arguments in these function to what you want
>anyway.
>

Let me note here that the first parameter is accepted without note by the 
compiler. If I call AddLNode as  AddLNode(&Head,(void *)Tlist); my
compiler warnings go away, also, the Turbo C IDE points to the second parm
as the source of my error.  It seems to accept the first one fine.


Cheers!
Steve


-- 
----------------------------------------------------------------------------
{apple|pyramid|sun}!octopus!stever} Disclaimer: I speak only for me! 8-)
Flames, grammar errors, spelling errrors >/dev/nul
----------------------------------------------------------------------------