offsetof() macro

T

Tim Rentsch

Keith Thompson said:
I've used other languages that have a keyword that's used as the
equivalent of a null pointer constant, and that don't allow any other
form of null pointer constant. I'll just mention that programmers in
those languages typically don't know or care how null pointers are
represented; even if they happen to know how a given implementation
represents null pointers, they don't try to make use of the knowledge.
And their FAQs don't have to devote an entire section to null
pointers.

Sure; certainly there are some benefits to the 'nil' approach.

I don't think there are any costs to this approach, apart from the
insurmountable cost of all the existing C code that would be broken.

In my experience these kinds of design choices essentially always
carry ongoing costs as well as benefits. That isn't to say that the
benefits won't outweigh the costs necessarily, only that there also
are costs to consider. So if you aren't aware of any costs besides
the cost of converting existing code, maybe you haven't considered
the ramifications fully enough yet?

To put this another way, when C was being designed, there already were
languages with, eg, NULL to indicate null pointers (and no other forms
allowed). Yet KT and/or DR decided to use 0 for null pointers, so
they must have thought there were some benefits to doing that over
using NULL. If the original C model has some benefits, then giving
those up is a cost.

I'm almost tempted to suggest adding a "nil" keyword to the next C
standard, with the obvious semantics, *without* eliminating the other
forms of null pointer constant. But providing a better approach
without removing the old one would just add to the confusion.

Why not just use NULL? A lint-like tool, or a compiler warning
switch, could be used to flag those cases where a pointer value is
needed yet a null pointer constant other than NULL is used. That
approach seems more likely to get to where you hope to get to.
 
K

Keith Thompson

Tim Rentsch said:
Sure; certainly there are some benefits to the 'nil' approach.


In my experience these kinds of design choices essentially always
carry ongoing costs as well as benefits. That isn't to say that the
benefits won't outweigh the costs necessarily, only that there also
are costs to consider. So if you aren't aware of any costs besides
the cost of converting existing code, maybe you haven't considered
the ramifications fully enough yet?

To put this another way, when C was being designed, there already were
languages with, eg, NULL to indicate null pointers (and no other forms
allowed). Yet KT and/or DR decided to use 0 for null pointers, so
they must have thought there were some benefits to doing that over
using NULL. If the original C model has some benefits, then giving
those up is a cost.

C was based on a couple of earlier languages. BCPL, if I recall
correctly, was a low-level language that treated all of memory as an
array of words; pointers were effectively indices into that array.

Conceivably there might be some advantage (other than historical) in
C's approach rather than defining single keyword for null pointers. I
just can't think of anything. Can you?
Why not just use NULL? A lint-like tool, or a compiler warning
switch, could be used to flag those cases where a pointer value is
needed yet a null pointer constant other than NULL is used. That
approach seems more likely to get to where you hope to get to.

I have no real hope of getting anywhere with this.
 
T

Tim Rentsch

Keith Thompson said:
Actually, we aren't in agreement. I think the issue is (reasonably)
clear-cut.

I don't see any inconsistency between saying the issue is reasonably
clear-cut and saying the issue is not clear cut. There's a difference
in degree between the two statements, but they aren't inconsistent.

So I'm not sure that I can agree that we aren't in agreement. :)

Agreed. However, there are cases where the standard gives explicit
permission to do something in an implementation-defined way, such as
the declaration of main(). The fact that it doesn't do so here is,
IMHO, significant.

Saying you believe it's significant isn't really a very convincing
argument, is it?

More specifically, look at the wording of 5.1.2.2.1, where 'main' is
specified. Clearly paragraph 1 intends to give a precise
specification of 'main'; in particular, the word "shall" is used.
The wording used in 6.3.2.3 p3 is quite different. The analogy
just doesn't seem strong enough to be very convincing.

Since there's a clear and unambiguous interpretation assuming the
definition is exhaustive, I believe that's the best interpretation.

If you want to believe that, it's ok with me. But your statement
doesn't offer me any reason why I should believe it.

Furthermore, there's an obvious reason not to believe it, which is
that interpreted as an exhaustive definition, the given wording is
clearly incomplete since it doesn't cover things like '((void*)0)'.

The standard doesn't give explicit permission for other forms of null
pointer constant. Using (void*)42 in a context that requires a null
pointer constant is a constraint violation. An implementation that
doesn't issue a diagnostic for such a use is non-conforming.

Saying an implementation that doesn't issue a diagnostic for such a
use must be non-conforming is predicated on the assumption that
implementation-defined null pointer constants aren't allowed. It's
circular reasoning.

On the other hand, an implementation certainly is free to choose a
representation for pointers where any address under, say, 100 is to be
interpreted as a null pointer. On such an implementation, it would be
perfectly reasonable for '(void*)42' to be allowed as a null pointer
constant.

Similarly, the standard doesn't give permission for other forms of
integer constants. An implementation can accept 0b11001001 as a
binary constant as a language extension, but it must issue a
diagnostic for any such constant in conforming mode.

Not the same thing at all. The form of integer constants is specified
by syntax rules; these rules have a precise and exact meaning. I
don't have a reference handy, but I believe there is a statement in
the Standard to the effect that a syntax violation must result in a
diagnostic. Certainly using an implementation-defined null pointer
constant *might* result in a diagnostic being issued, but I don't know
of any provision that *requires* one.

The term "implementation-defined" doesn't just mean that the
implementation gets to make a choice; it also means it has to document
that choice. If the standard merely said that NULL expands to a null
pointer constant, an implementation wouldn't be required to document
what it actually expands to. This would be no great loss, since code
shouldn't depend on the choice, but I believe the intent is that (a)
an implementation can choose any valid null pointer constant as the
expansion of NULL, and (b) it must document what choice it makes.

That's a plausible interpretation. However, that interpretation seems
better expressed by saying, eg, "NULL expands to a null pointer
constant; the choice of which null pointer constant is implementation
defined." You haven't really given any kind of convincing reason,
merely stated that you believe that's the intent. In the absence of
any such reason, allowing NULL to define an implementation-defined
null pointer constant seems like a better fit to the existing
language, because otherwise that language would probably have been
rewritten to better express the intent you suggest.

It wouldn't make sense to use the phrase "implementation defined" only
in a footnote.

I agree that it's better to put the "implementation defined" phrase
in the main text, in either interpretation; as mentioned above.

I believe the glitch in 6.3.2.3p3, which implies that (void*)0 is a
null pointer constant but ((void*)0) isn't, is simply an oversight. I
suspect the authors of the standard just assumed that an expression in
parentheses is equivalent to the expression without parentheses -- and
of course enclosing macro definitions in parentheses is almost always
a good idea. Implementations actually conform to the intent of the
standard in this case, rather than to the literal wording. I wouldn't
infer anything significant from this (though I'd certainly like to see
this corrected.)

A small correction - implementations conform to what *you presume* the
intent of the standard is. If implementation-defined null pointer
constants are allowed, then they may be conforming to the actual
standard and not just to the intent.

If your suspicion about simply forgetting about enclosing parentheses
were right, then other more complicated forms of "null pointer
constants" shouldn't work. Have you tried any of these? If not
you may be surprised by what you find.

I disagree. I find it much simpler to assume that the definition of
"null pointer constant" means exactly what it says, modulo the
parentheses glitch. The intent of the phrase "implementation-defined
null pointer constant" in 7.17p3 is quite clear given this
interpretation; there's no need to invent the idea of additional
implementation-defined *forms* of null pointer constant. There's also
no advantage in doing so; we have more than enough null pointer
constants already without allowing implementations to invent their
own.

If I may paraphrase, what you think is that the document authors
screwed up, because your interpretation is simpler? Or is it
the other way around?

Perhaps that was a little unfair. But I don't see any real substance
here; if one assumes your position, then everything is consistent and
clear. However that's equally true for the other position. I don't
see any reason, on those grounds, that anyone should prefer one
position over the other.
 
K

Keith Thompson

Tim Rentsch said:
If I may paraphrase, what you think is that the document authors
screwed up, because your interpretation is simpler? Or is it
the other way around?

Perhaps that was a little unfair. But I don't see any real substance
here; if one assumes your position, then everything is consistent and
clear. However that's equally true for the other position. I don't
see any reason, on those grounds, that anyone should prefer one
position over the other.

There's not a whole lot more to be said, but I've just posted a
question to comp.std.c. Perhaps we can get an interpretation from the
folks who actually wrote the standard.
 
T

Tim Rentsch

Keith Thompson said:
Conceivably there might be some advantage (other than historical) in
C's approach rather than defining single keyword for null pointers. I
just can't think of anything. Can you?

I have my own opinions about what some of these are,
but perhaps we can get some other regulars to voice
their opinions on the subject. I don't want to get
involved in a debate about the relative merits of
the two approaches.
 

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

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,096
Latest member
ThurmanCre

Latest Threads

Top