ju**********@ya hoo.co.in wrote:
According to Section A6.6 Pointers and Integers (k & R)
" A pointer to one type may be converted to a pointer to another type.
The resulting pointer may cause
addressing exceptions if the subject pointer does not refer to an
object suitably aligned in storage. It is
guaranteed that a pointer to an object may be converted to a pointer to
an object whose type requires less
or equally strict storage alignment and back again without change; the
notion of ``alignment'' is
implementation-dependent, but objects of the char types have least
strict alignment requirements. As
described in Par.A.6.8, a pointer may also be converted to type void *
and back again without change. "
It says that it is *guaranteed* that a pointer to an object may
be converted to an object whose type require equally stringent
storage alignment. My question is that since two pointer variables
may be of different size (as pointed out by lots of people
in this newsgroup ) how this could be possible ? It may be possible
that two pointer variables of different types have same
byte alignment restrictions but their sizes may be different. Under
these conditions how can we convert one to another ?
I would say that two pointer variables of different types
should never be allowed to convert from one type to other, because
same byte alignment does not mean same pointer variable size.
If the sizes differ the compiler has to insert code (you should
but don't have to tell it by casting) to make the conversion work
out right. But it's only required to do so reasonably if the align-
ment restrictions of the type you convert to aren't stricter than
of the type you're converting from. A conversion of bit represen-
tations of pointers is not uncommon, e.g. a NULL pointer doesn't
have to have a binary representation where all bits are 0, but you
can compare a NULL pointer (e.g. returned by from malloc()) with
the value 0 anyway and the result must be true, even though the
NULL pointer when cast to an int (assuming equal sizes) wouldn't
result in the number 0 [1]. So the compiler has to insert code that
makes the result of this comparison come out correctly. And for a
legitimate conversion (i.e. one where the above rules about align-
ment restrictions are satisfied) between pointers of types which are
stored with different sizes the compiler also has to ensure that
this works correctly if it's a standard compliant C compiler [2].
Secondly, section A.6.8 says that "previously char * pointers
played the role of generic (void) pointers"
Is this true presently also ?
Consider the following piece of code:
#include <stdlib.h>
int main(void)
{
unsigned char *c;
int *i;
i = malloc(sizeof(i nt));
c = i;
}
On comlilation, I get the warning,
cc: Warning: t.c, line 8: In this statement, the referenced type of the
pointer value "i" is "int", which is not compatible with "unsigned
char". (ptrmismatch)
c = i;
--------^
If char pointer can play the role of generic pointer, why I
am getting this warning ?
It's a warning, not an error, telling you that you may be doing
something stupid. Not more and not less. The compiler will probably
assume that you know what you're doing when you would do the conver-
sion with an explicit cast (but it still could emit a warning, there
is no restriction in the standard what a compiler can complain about),
so it might let you get away with an explicit cast. But since an
assignment between different types is something potentially dangerous
the compiler here tries to help you. It's the same as getting a war-
ning for e.g.
if ( x = malloc( 100 * sizeof *x ) )
There's nothing inherently wrong with this, but most compilers will
still tell you that you may unintenionally be doing an assignment
instead of a comparison here since getting '=' and '==' mixed up
in an if-condition is such a common mistake.
Moreover, as you cite yourself, char pointers "previously " played
the role of generic pointers - that was before the C standard came
out, finally making the void pointer type mandatory and giving
it some magical qualities, i.e. requiring that all pointer types
can be converted to and from a void pointer (at the cost that
you can't dereference a void pointer). Actually, a char pointer
still has to have the same representation and alignment require-
ments as a void pointer, but since char pointers aren't a poor
mans "ersatz" for a true generic pointer anymore compilers tend
to point out also implicit conversions to a char pointer from a
different pointer type as suspicious.
Regards, Jens
[1] This is also the reason why forgetting to include <stdlib.h>
when you use malloc() and instead casting the return value
is not guaranteed to work. If <stdlib.h> isn't included the
compiler assumes that malloc() returns an int and thus mind-
lessly converts the return value of malloc() to an int (per-
haps even passing the value back to the caller via an data
only register - there are several architectures that have
different registers for data and addresses). Only then it does
the explicit conversion, now converting from an int to the
intended pointer type. But since a pointer is not necessarily
the same as its representation when interpreted as an int this
can result in "interestin g" and probably unintended results,
e.g. a NULL pointer returned by malloc() becoming converted
to a non-NULL pointer on a machine where a NULL pointer is
not represented by all bits 0.
[2] Obviously, the implementor of a compiler for a machine where
different pointer types have different sizes has some problems
on his hands. One possible solution would by to use the size
required by the largest pointer type for storing all pointers,
even if that would cost some additional memory. Another one
would be to give up one writing a standard compliant C com-
piler like they did for DOS, where they invented new qualifiers
for pointers (i.e. far, huge etc.). Or perhaps on the target
machine there are some special tricks to solve the problem
(i.e. having a special bit stored with small sized pointers
that gets set when a pointer value from a larger sized pointer
gets stored in it and then indicates that it doesn't hold the
"real" address but just a pointer to another address where the
full-sized address can be found. And there are probably some
more clever ways I wouldn't know about, not being a C compiler
implementor.
--
\ Jens Thoms Toerring ___
Je***********@p hysik.fu-berlin.de
\______________ ____________
http://www.toerring.de