[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::decc

Title:DECC
Notice:General DEC C discussions
Moderator:TLE::D_SMITHNTE
Created:Fri Nov 13 1992
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:2212
Total number of notes:11045

2128.0. "Errant PTRMISMATCH?" by TURRIS::SFRANC::GAISFORD (Phil Gaisford, RTR Eng., DTN 381 0790) Wed Mar 26 1997 16:27

DECC V5.5-003
OpenVMS Alpha V6.2,V7.1

The following compiles cleanly using V5.4, but generates a warning when compiled
with V5.5-003:

#include    <builtins.h>
typedef struct qhdr
    {
    long flink;
    long blink;
    } qhdr;

#pragma inline remqr
static int remqr(qhdr *entry, qhdr **removed_entry)
{
int status;
qhdr *prev;

prev = (qhdr *)(entry->blink + (char *)entry);

status = _REMQHI(prev, removed_entry);

return(status);
}


======


status = _REMQHI(prev, removed_entry);
.........^
%CC-W-PTRMISMATCH, In this statement, the referenced type of the pointer value "
(removed_entry)" is "pointer to struct qhdr", which is not compatible with "poin
ter to void".

Is this a valid complaint??
T.RTitleUserPersonal
Name
DateLines
2128.1MOIRA::FAIMANWandrer, du M�der, du bist zu HausWed Mar 26 1997 17:0421
> %CC-W-PTRMISMATCH, In this statement, the referenced type of the pointer value "
> (removed_entry)" is "pointer to struct qhdr", which is not compatible with "poin
> ter to void".
>
> Is this a valid complaint??

Yes.

A "pointer to <anything>" can be converted freely to and from a "pointer to void";
but they do not necessarily look anything alike.  (I.e., there is not guarantee that
the representation of a given pointer value as a "pointer to <type>" is the same as
the representation of that same pointer value as a "pointer to <void>".

Consequently, a "pointer to pointer to <type>" is *not* freely convertible with a
"pointer to pointer to void", anymore than a "pointer to int" is freely convertible
with a "pointer to short".

You can only convert between "pointer to <type1>" and "pointer to <type2>" if <type1>
and <type2> are more-or-less the same type.  In this case, <type1> is "pointer to <type>
and <type2> is "pointer to to void"; and, while "pointer to <type>" and "pointer to void"
are mutually convertible types, they are not the *same* type.
2128.2I'm confusedCXXC::REPETERich Peterson 381-1802 ZKO2-3/N30Wed Mar 26 1997 20:1352
Two things:

> The following compiles cleanly using V5.4

Can you check this?  We never shipped a V5.4 of DEC C.

> but generates a warning when compiled with V5.5-003:

I cannot reproduce this behavior using the header files and
compiler in the V5.5-003 kit.

Might you have your own copy of builtins.h?

Neil is correct as far as what the compiler ought to do given
a function being passed an argument of type qhdr ** when the
prototype parameter is of type void **.  But here the prototype
is coming from builtins.h, which is also part of the compiler
kit.  But of course if your compiler is using a different
copy of this header file, it could contain almost anything.

Not to say that builtins.h is necessarily "perfect".  But looking
at its content, what's apparently supposed to happen on Alpha
is that this function is provided by two aspects of the header:


/* 
**  Remove entry from longword queue
*/
int __PAL_REMQHIL(void *__head, void **__removed_entry);    /* At head,
interlocked */
/*
**  Macros for translation from VAX C to DEC C ALPHA builtins
*/
 #define _REMQHI(head, removed_entry) 			\
  (((0x0c >> (__PAL_REMQHIL((head), (void **)(removed_entry))+1)) + 1) & 3)

So there is indeed a prototype with second parameter void**, which would
not match your argument, but the _REMQHI macro that you use should
be providing a cast that would fix the problem.  Since your testcase
doesn't issue the warning when I compiled with the V5.5 header, I
can only conclude you must have a different version of the header.

I'm not certain whether the use of void** in the prototype was
originally expected to allow passing any kind of pointer-to-pointer
and the cast was added to the macro to get rid of the message,
or if the prototype was declared with void** as an aid to human
understanding that this is a a pointer-to-pointer used to return
a pointer value to the caller.  The prototype could be correctly
written without the need for a cast in the macro by just declaring
the second parameter void*, but that suggests to the reader that
both parameters are the same kind of thing when in fact the second
is a pointer to the kind of thing the first parameter is.
2128.3Compiler is right, header file is wrongDECCXX::RMEYERSRandy MeyersWed Mar 26 1997 20:2931
Re: .0

Although Neil is entirely correct in .1 that a pointer to pointer to void
doesn't have the magic property that it is compatible with any other type
of pointer, I suspect that there might be a problem with builtins.h.

The intent is that _REMQHI allow any type of pointer as its second argument
(but the second argument just better point to a pointer to receive the
address of the removed queue entry).

The latest development source for builtins.h seems to do the right thing:

#define _REMQHI(head, removed_entry)                    \
      (((0x0c >> (__PAL_REMQHIL((head), (void **)(removed_entry))+1)) + 1) & 3)

regardless of the type of removed_entry, it will be cast to void ** before
calling __PAL_REMQHIL, which does want a void ** for its second argument.

Of course, __PAL_REMQHIL (and its friends) probably shouldn't have its
second argument defined as a void **.  The second argument should be a
void * (so it is compatible with any type of pointer).  Again, that
void * argument will just happen to point at another pointer that will
receive the removed entry.

You can work around this problem by adding a cast to void * in your call:

	status = _REMQHI(prev, (void *) removed_entry);

The workaround will always work, regardless of any future changes to the
type of the second parameter to _REMQHI and __PAL_REMQHIL, since the compiler
will cheerfully convert a void * to any pointer type of parameter.
2128.4void * was the intentDECCXX::RMEYERSRandy MeyersWed Mar 26 1997 21:0671
Re: .2

>I'm not certain whether the use of void** in the prototype was
>originally expected to allow passing any kind of pointer-to-pointer
>and the cast was added to the macro to get rid of the message,
>or if the prototype was declared with void** as an aid to human
>understanding that this is a a pointer-to-pointer used to return
>a pointer value to the caller.

The original intent was that the queue builtins allow any type of pointer
type to be used as the second argument.  The second argument just better
be a pointer that happens to point at another pointer that will be updated
with the value of the removed queue entry.

VAX C has the builtins tightly built into the compiler, and so it could
follow special rules for the type checking for the builtins that could
not be expressed in the C language.  VAX C insisted that the second
argument be a pointer to a pointer to any type.  The only requirement was
that the second argument have two levels of pointer in its type.

C does not have this concept.  "void *" allows you to say "pointer to
anything", but as Neil stated in .1, "void **" specifically says you
have a pointer that must point to a "void *".

The VAX C manual did describe the "prototypes" for the queue builtins
using types like "void **".  This was as much as a documentation error
(and I wrote the first draft of that section) as it was an attempt to
explain clearly two levels of pointer were required for the parameters
in question.

DEC C implemented the builtins as C functions that are turned into
special machine code at the last minute.  As such, the arguments
needed to be described in terms of actual C language function prototypes.
(VAX C never really had prototypes for these builtins since they were
"built-into" the compiler.)  I remember a conversation from long ago
where I recommended that the parameters turn into just "void *", since
that was the most accurate description of the intended behavior.
Instead, I suspect someone just typed in the prototypes from the VAX
C manual.

>The prototype could be correctly
>written without the need for a cast in the macro by just declaring
>the second parameter void*, but that suggests to the reader that
>both parameters are the same kind of thing when in fact the second
>is a pointer to the kind of thing the first parameter is.

The prototypes for the queue instructions should just declare the second
parameter as void *.  Comments or some other technique should be used to
warn the user that the void * must point at another pointer.

I sort of like:

	/* This typedef is used when a pointer must point to another pointer */
	typedef void *__ptr_to_ptr;

	int __PAL_REMQHILR(void *__head, __ptr_to_ptr __removed_entry);
	int __PAL_REMQTILR(void *__head, __ptr_to_ptr __removed_entry); 

etc.



Re: .0

You can work around this problem by adding a cast to void * in your call:

	status = _REMQHI(prev, (void *) removed_entry);

The workaround will always work, regardless of any future changes to the
type of the second parameter to _REMQHI and __PAL_REMQHIL, since the compiler
will cheerfully convert a void * to any pointer type of parameter.
2128.5Not just "latest development"CXXC::REPETERich Peterson 381-1802 ZKO2-3/N30Wed Mar 26 1997 22:1820
RE .4:

> Re: .0
>
> You can work around this problem by adding a cast to void * in your call:

That's true, I'm sure your account of the actual historical origins
of the use of void** in the prototypes is correct, and I agree the
__ptr_to_ptr typedef is a nice way to eliminate the ill-effects of
this inappropriate use of void** (though a macro might be better in
case other header files would want to do this).

But the mystery still remains as to why .0 saw this problem at all.
I pulled the builtins.h header out of the decc$rtldef.tlb library
in the V5.5-003 kit and verified that it has the same cast as the
current development sources, and that the posted testcase does not
provoke the message when using that version of the header.

Either the version reported in .0 is incorrect, or there is something
broken in the environment being used there.
2128.6Oops - ancient decc$rtldef.tlb in sys$specific...TURRIS::SFRANC::GAISFORDPhil Gaisford, RTR Eng., DTN 381 0790Thu Mar 27 1997 17:4814
The culprit would appear to be the following ancient copy of a text library
in the system-specific part of sys$share:

Directory SYS$SYSROOT:[SYSLIB]

DECC$OLB.OLB;1         3933  28May93 12:35:16  [SYSTEM]      (RWED,RWED,RE,)
DECC$RTLDEF.TLB;1       321  28May93 13:56:42  [SYSTEM]      (RWED,RWED,RE,)

Removing this resolved the problem.

To answer an earlier question, we were previously using V5.3-006, and not V5.4
as stated.

Thanks everyone for your insightful contributions.