This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: pointer <-> integer conversion warnings (bogus -Wall warnings)
- From: Tom Lord <lord at emf dot net>
- To: gcc at gcc dot gnu dot org
- Date: Thu, 14 Mar 2002 11:02:16 -0800 (PST)
- Subject: Re: pointer <-> integer conversion warnings (bogus -Wall warnings)
- References: <17B78BDF120BD411B70100500422FC6309E4D1@IIS000>
Dautrevaux@microprocess.com
just try to use a ix86 (x >= 3) in segmented mode: pointers
are 48 bits (segment + offset) while both size_t and ptrdiff_t
(that were not proposed but could have been) are 32 bits as no
object can be bigger than a 4Gb segment.
Sure. Similarly, I was thinking of future systems with a huge address
space, a smaller per-process address space, and virtual memory
hardware that would be slightly exotic by today's common expectations.
However for such a system I don't think "x = (int)p" could
have ANY useful meaning which will NOT loss some importabnt
daat needed to be able to successfully do "p = (void*)x"
later
Let's suppose that the value being converted back and forth between
the two variables is not an address, but a range-limited integer.
My understanding is that:
1. The standards do not _guarantee_ that the round trip
conversion from such an integer to pointer to integer
gives the same integer (unless the integer is 0). In an
absolute sense, you're right that it's not portable.
2. One intention of the default conversion in the language is
that, for a small enough, not necesarilly 0 integer, the
round trip will give the same integer. It's hard to
imagine any implementation that won't, in fact, get this
"right", treating:
p = (void *)x;
as equivalent to:
p = (void *)((char *)0 + x);
and
x = (int)p;
as equivalent to:
x = (int)((char *)p - (char *)0);
If we want to be extra careful using this feature, it's
reasonable to make sure that p is of type `void *'.
A common and good use for this is a `void *' parameter
passed in parallel with a function pointer (a "thunk" or
"closure") and propogated blindly to calls through the
function pointer. Callers can pass a pointer to any type
or a suitably range-limited integer cast to 'void *'.
3. The default conversion is, in fact, part of the language.
It can be invoked implicitly, or explicitly with a cast.
A traditional way to use this feature is to always mark
it's intentional uses with a cast: code which invokes it
implicitly is a mistake and helpful compilers give warnings
about that.
4. There are all kinds of correctness analyses that can be
performed on C programs that go far beyond what you'd
expect a C compiler to do. Some of these are strong enough
to only find bugs; some of these will only find code that
should be carefully reviewed. Such analyses are so
open-ended, imprecise, and unrelated to compilation, that a
good strategy is to package them in tools like `lint'.
You might even add extra annotation to your program to help
lint-like tools be more accurate. Three levels of
meaning for "this is clean code" are:
a. it compiles
b. it compiles with all the usual warnings
enabled, without generating any warnings
c. it passes inspection by <your favorite lint tools>
Historically GCC has had the nice property that it includes, as an
option, the ability to generate some warnings that older compilers
left for lint. `printf' format checking is a nice example. I even
appreciate adding `panic' calls in unreachable code where GCC can't
figure out that it is unreachable ("return from non-void function"
errors).
However, such features never kept GCC from providing the levels of
checking (a) and (b) in the list above. Now, with the
pointer<->integer conversion warnings enabled by default and by
'-Wall', level (b) is gone. Simply rethinking what options it takes
to enable the warnings would restore the traditional and useful
behavior, but I'm assured it's "not going to happen" and that I'd
better just "live with it".
So only the double cast could be used to silent the
"differing-sizes" warning.
When I first wrote this message, I said:
Correct use of the double cast trick is only available to code
that wants to rely on `intptr_t'. It's a nice side-effect of
the way the warning is implemented that the double cast trick
works, but that's not a reason to enable the warning by
default, or to not provide an option that does what `-Wall'
did only a few years ago (the GCC branch I use, which doesn't
have this bug, comes from 1999).
but thinking further about it, the double cast trick isn't even
guaranteed to work in the presence of `intptr_t' since aren't we
only guaranteed that `intptr_t' is large enough -- not that it isn't
too large? (That's not a rhetorical question: I don't have a C99 spec.)
(C99 has known-width integer types, right? Are those of a specific
width? or just a specific minimum width?)
> On the other hand, heck, _why_not_ just make GCC less of a
> real C compiler in _just_one_more_ way. Who cares? What
> difference does it make, _really_? Especially if it means
> _rth_wins_!
Don't follow you there.
Well, I thought rth's "live with it" was pretty much over the top. It
points to a long-standing attitude problem with GCC (that long
predates rth's involvement). It points to more recent problems with
figuring out the design of GCC now that it's an element of commercial
services: would I have been told to "live with it" if I said "Here's
$250,000, please give me some -W options that work in the more
traditional way and can we please reconsider the defaults"? I replied
in kind. Such is email.
Someone off-list said "You should make patches for this." First,
a reply like "live with it" suggest to me that such patches won't
be accepted. Second, there's a design issue here -- it's a question
larger in scope than just "what changes would fix this specific bug".
I think the efforts of *all* GCC
developpers is to make GCC a *more* real C compiler, not a
less one, and to solve all the cases where it is not :-) And
BTW I care! I've lost too many days in debugging small errors
that should have generated warnings if the compilers I used
then (some years ago) had been smart enough to warn me that I
was losing daat in a conversion I was thinking was safe
reading the code, like "x = (int)p;" where it happens that x
is a short but you have to go up 40 plines to notice it ;-(
Of course perhaps we don't have the same idea of what a real C
compiler is; for me it's a compiler that hepls me writing
*good* code and avoiding dangerous constructs.
Support for levels (a) and (b) of the three levels of clean code
listed above is something I consider to be an essential property of a
real C compiler: a conceptually simple entity that is easy for
programmers to control and that has a natural relationship to the
language, sometimes augmented with fancy optimizations and combined
(in tasteful ways) with features from tools like `lint'. Trying to
force me to change public interfaces to perfectly reasonable
libraries, switch to C99 at too early a date, or break code that uses
those interfaces in order to shut up a default and `-Wall' warning
that's inspired by the frustrations someone had porting Linux to
alpha contributes to the sensation of using a C compiler maintained by
people who don't like C. But then, I'm the sort of dinosaur who
thinks it will be a stunning improvment the day that GCC distributions
start including a _second_ compiler that's similar in size and
complexity to, say, lcc or the Plan 9 compiler. That, and an
extensible `lint'.
-t