Re: Ike Naar

Discussion in 'C Programming' started by Stephen Sprunk, Feb 8, 2009.

  1. Malcolm McLean wrote:
    >
    > "Han from China" <> wrote in message news:
    >> Ike Navar wrote:
    >>> If NULL is defined as plain 0 then an int is passed to the function
    >>> where it expects a char*.

    >>
    >> Anyway, the classic Unix case is the execl() function. If NULL is
    >> defined as ((void *) 0), the unadorned NULL works, but if NULL
    >> is defined as 0, we have the problem you mention.
    >>

    > Surely there is some rule that NULL can be used as the null pointer
    > constnant, in all contexts?


    Nope. NULL is allowed to be defined as 0, in which case it only becomes
    a null pointer constant when converted to a pointer; in other contexts,
    it's simply an integer. However, this should only matter when used as
    an argument to a variadic function; one must cast to an appropriate
    pointer type (such as (void*)) in that case. To avoid this common
    error, NULL is usually defined as (void*)0 on many implementations --
    but that's not required, and for maximum portability one should not
    depend on it.

    S

    --
    Stephen Sprunk "Stupid people surround themselves with smart
    CCIE #3723 people. Smart people surround themselves with
    K5SSS smart people who disagree with them." --Isaac Jaffe
    Stephen Sprunk, Feb 8, 2009
    #1
    1. Advertising

  2. pete <> writes:

    > Stephen Sprunk wrote:
    >> Malcolm McLean wrote:
    >>>
    >>> "Han from China" <> wrote in message news:
    >>>> Ike Navar wrote:
    >>>>> If NULL is defined as plain 0 then an int is passed to the function
    >>>>> where it expects a char*.
    >>>>
    >>>> Anyway, the classic Unix case is the execl() function. If NULL is
    >>>> defined as ((void *) 0), the unadorned NULL works, but if NULL
    >>>> is defined as 0, we have the problem you mention.
    >>>>
    >>> Surely there is some rule that NULL can be used as the null pointer
    >>> constnant, in all contexts?

    >>
    >> Nope. NULL is allowed to be defined as 0, in which case it only
    >> becomes a null pointer constant when converted to a pointer; in
    >> other contexts, it's simply an integer.

    >
    > 0 is a null pointer constant. That's all, no context.
    >
    > N869
    > 6.3.2.3 Pointers
    > [#3] An integer constant expression with the value 0, or
    > such an expression cast to type void *, is called a null
    > pointer constant.


    It is also an integer constant or 6.3.2.3 would not apply. It is
    clearly both at the same time so why do you seem to be suggesting that
    context does not matter?

    --
    Ben.
    Ben Bacarisse, Feb 9, 2009
    #2
    1. Advertising

  3. Ben Bacarisse <> writes:
    > pete <> writes:
    >> Stephen Sprunk wrote:
    >>> Malcolm McLean wrote:

    [...]
    >>>> Surely there is some rule that NULL can be used as the null pointer
    >>>> constnant, in all contexts?
    >>>
    >>> Nope. NULL is allowed to be defined as 0, in which case it only
    >>> becomes a null pointer constant when converted to a pointer; in
    >>> other contexts, it's simply an integer.

    >>
    >> 0 is a null pointer constant. That's all, no context.
    >>
    >> N869
    >> 6.3.2.3 Pointers
    >> [#3] An integer constant expression with the value 0, or
    >> such an expression cast to type void *, is called a null
    >> pointer constant.

    >
    > It is also an integer constant or 6.3.2.3 would not apply. It is
    > clearly both at the same time so why do you seem to be suggesting that
    > context does not matter?


    Yes, 0 is both an integer constant and a null pointer constant. I
    think pete's point (which I agree with) is that 0 is a null pointer
    constant (or at least is "called" a null pointer constant) regardless
    of the context in which it appears. The 0 in:
    int x = 0;
    is by definition a null pointer constant, even though it's not
    converted to a pointer type.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 9, 2009
    #3
  4. Stephen Sprunk

    Richard Guest

    Keith Thompson <> writes:

    > Ben Bacarisse <> writes:
    >> pete <> writes:
    >>> Stephen Sprunk wrote:
    >>>> Malcolm McLean wrote:

    > [...]
    >>>>> Surely there is some rule that NULL can be used as the null pointer
    >>>>> constnant, in all contexts?
    >>>>
    >>>> Nope. NULL is allowed to be defined as 0, in which case it only
    >>>> becomes a null pointer constant when converted to a pointer; in
    >>>> other contexts, it's simply an integer.
    >>>
    >>> 0 is a null pointer constant. That's all, no context.
    >>>
    >>> N869
    >>> 6.3.2.3 Pointers
    >>> [#3] An integer constant expression with the value 0, or
    >>> such an expression cast to type void *, is called a null
    >>> pointer constant.

    >>
    >> It is also an integer constant or 6.3.2.3 would not apply. It is
    >> clearly both at the same time so why do you seem to be suggesting that
    >> context does not matter?

    >
    > Yes, 0 is both an integer constant and a null pointer constant. I
    > think pete's point (which I agree with) is that 0 is a null pointer
    > constant (or at least is "called" a null pointer constant) regardless
    > of the context in which it appears. The 0 in:
    > int x = 0;
    > is by definition a null pointer constant, even though it's not
    > converted to a pointer type.


    Never was I so confused.

    I now discover

    char *p = 0; /* is the preferred way to create a null pointer +/

    And since 0 converts to false in a boolean expression then

    if(p){
    }

    is perfectly valid and the NULL check is completely irrelevant since the
    internal representation does not come into it. The 0 value is all that
    matters.

    Which is brilliant since this is how I treated ptrs for years before
    getting quite a nasty shock in c.l.c where I was told I was being
    sloppy.
    Richard, Feb 9, 2009
    #4
  5. Keith Thompson <> writes:

    > Ben Bacarisse <> writes:
    >> pete <> writes:
    >>> Stephen Sprunk wrote:
    >>>> Malcolm McLean wrote:

    > [...]
    >>>>> Surely there is some rule that NULL can be used as the null pointer
    >>>>> constnant, in all contexts?
    >>>>
    >>>> Nope. NULL is allowed to be defined as 0, in which case it only
    >>>> becomes a null pointer constant when converted to a pointer; in
    >>>> other contexts, it's simply an integer.
    >>>
    >>> 0 is a null pointer constant. That's all, no context.
    >>>
    >>> N869
    >>> 6.3.2.3 Pointers
    >>> [#3] An integer constant expression with the value 0, or
    >>> such an expression cast to type void *, is called a null
    >>> pointer constant.

    >>
    >> It is also an integer constant or 6.3.2.3 would not apply. It is
    >> clearly both at the same time so why do you seem to be suggesting that
    >> context does not matter?

    >
    > Yes, 0 is both an integer constant and a null pointer constant. I
    > think pete's point (which I agree with) is that 0 is a null pointer
    > constant (or at least is "called" a null pointer constant) regardless
    > of the context in which it appears.


    I thought he was saying a little bit more by "that's all" but I can
    see now that that is unlikely.

    His correction (that the context only determines whether it becomes a
    *null pointer*, not whether it is a null pointer constant) is quite
    correct, but I would have stressed that it is always both (since being
    both of these things is a very important part of 0) when making the
    correction.

    --
    Ben.
    Ben Bacarisse, Feb 9, 2009
    #5
  6. Richard <> writes:

    > Keith Thompson <> writes:
    >
    >> Ben Bacarisse <> writes:
    >>> pete <> writes:
    >>>> Stephen Sprunk wrote:
    >>>>> Malcolm McLean wrote:

    >> [...]
    >>>>>> Surely there is some rule that NULL can be used as the null pointer
    >>>>>> constnant, in all contexts?
    >>>>>
    >>>>> Nope. NULL is allowed to be defined as 0, in which case it only
    >>>>> becomes a null pointer constant when converted to a pointer; in
    >>>>> other contexts, it's simply an integer.
    >>>>
    >>>> 0 is a null pointer constant. That's all, no context.
    >>>>
    >>>> N869
    >>>> 6.3.2.3 Pointers
    >>>> [#3] An integer constant expression with the value 0, or
    >>>> such an expression cast to type void *, is called a null
    >>>> pointer constant.
    >>>
    >>> It is also an integer constant or 6.3.2.3 would not apply. It is
    >>> clearly both at the same time so why do you seem to be suggesting that
    >>> context does not matter?

    >>
    >> Yes, 0 is both an integer constant and a null pointer constant. I
    >> think pete's point (which I agree with) is that 0 is a null pointer
    >> constant (or at least is "called" a null pointer constant) regardless
    >> of the context in which it appears. The 0 in:
    >> int x = 0;
    >> is by definition a null pointer constant, even though it's not
    >> converted to a pointer type.

    >
    > Never was I so confused.


    Yes, there is still some confusion.

    > I now discover
    >
    > char *p = 0; /* is the preferred way to create a null pointer +/


    not everyone prefers it, but some do.

    > And since 0 converts to false in a boolean expression then
    >
    > if(p){
    > }
    >
    > is perfectly valid


    This is valid but not because of 0 converting to false in a boolean
    expression. At least, that phrase has enough vague parts to it that
    it is not clear what you mean.

    In the "if" you wrote p is not converted. An 'if' is defined in terms
    of the expression comparing equal (or not equal) to 0. When a pointer
    is compared to 0 it is the 0 that gets converted to a null pointer.
    This is why the test is safe and correct even when a null pointer has
    a representation that is not all bit zero.

    > and the NULL check is completely irrelevant since the
    > internal representation does not come into it.


    I can't follow this at all. The internal representation is what
    determines (sometimes rather obliquely) the value of p so it does come
    into it. What matters is whether p compares equal to a null pointer
    of the same type.

    What do you mean by the NULL check? It is guaranteed that given char *p:

    if (p)
    if (p == 0)
    if (p == NULL)

    are all the same.

    > The 0 value is all that matters.


    It is whether the pointer is or is not a null pointer that matters. I
    am not sure if that is what you mean by "the 0 value". 0 is both a
    pointer value and an integer value and C can't compare these two
    without converting one or the other. Everything is designed to work
    if the conversion goes one way:

    if (p) => if (p == 0) => 0 converts to a null pointer

    but it may not work if you force the conversion the wrong way:

    if ((int)p) => if ((int)p == 0) => 0 taken to be an int

    what happens here is implementation defined and a null pointer may not
    convert to (int)0.

    --
    Ben.
    Ben Bacarisse, Feb 9, 2009
    #6
  7. In article <>,
    Han from China <> wrote:
    ....
    >If you were managing a large C project, which would you prefer:
    >someone who's successfully written complex pieces of software
    >that are used by many people throughout the world but who doesn't
    >use the ISO-approved terms and definitions when talking C, or
    >someone who's written a whole series of small, buggy programs
    >but who redeems himself by being able to tell you about trap
    >representations and the subtle difference between
    >"int main() { ... }" and "int main(void) { ... }"?


    You're asking the wrong question. Who cares about what you would do if
    you were managing a large C project? Why bring that into the discussion?
    That is obviously OT to this group and not something any of the regs
    here have done in decades (if ever).

    Rather, you should be asking:

    If you were teaching a beginner's C class and needed to know how to
    prototype main() or whether or not you should cast the return value
    of malloc (*), which would you prefer: someone who redeems himself by
    being able to tell you about trap representations and similar trivia
    and thus obviously has a mind for useless trivia, or someone who's
    successfully written complex pieces of software that are used by
    many people throughout the world?

    (*) Or wanted to amuse the class with discussions of Shakespeare and/or
    dirty underware...

    P.S. On an an entirely different (and non-ironic) note, I have come to
    the conclusion that this newsgroup isn't about C (of course that is
    obvious), but rather, about *teaching* C. Think of this as like a
    "teacher's college", where people get together to discuss how best to
    teach something. As I've said before, the regs are really just
    frustrated (and/or, possibly, burned-out) teachers.
    Kenny McCormack, Feb 9, 2009
    #7
  8. Stephen Sprunk

    Guest

    On 9 Feb, 02:01, Richard <> wrote:
    > Keith Thompson <> writes:


    <snip>

    > > Yes, 0 is both an integer constant and a null pointer constant.  I
    > > think pete's point (which I agree with) is that 0 is a null pointer
    > > constant (or at least is "called" a null pointer constant) regardless
    > > of the context in which it appears.  The 0 in:
    > >     int x = 0;
    > > is by definition a null pointer constant, even though it's not
    > > converted to a pointer type.

    >
    > Never was I so confused.
    >
    > I now discover
    >
    > char *p = 0; /* is the preferred way to create a null pointer +/
    >
    > And since 0 converts to false in a boolean expression then
    >
    > if(p){
    >
    > }
    >
    > is perfectly valid and the NULL check is completely irrelevant since the
    > internal representation does not come into it. The 0 value is all that
    > matters.


    ah, but I believe (meaning I can' remember where I read it)
    that this is problematic

    assert (p);

    that it needs to be replaced with

    assert (p != 0);

    to be safe


    > Which is brilliant since this is how I treated ptrs for years before
    > getting quite a nasty shock in c.l.c where I was told I was being
    > sloppy.




    --
    Nick Keighley
    , Feb 9, 2009
    #8
  9. Stephen Sprunk

    Richard Guest

    Ben Bacarisse <> writes:

    > Richard <> writes:
    >
    >> Keith Thompson <> writes:
    >>
    >>> Ben Bacarisse <> writes:
    >>>> pete <> writes:
    >>>>> Stephen Sprunk wrote:
    >>>>>> Malcolm McLean wrote:
    >>> [...]
    >>>>>>> Surely there is some rule that NULL can be used as the null pointer
    >>>>>>> constnant, in all contexts?
    >>>>>>
    >>>>>> Nope. NULL is allowed to be defined as 0, in which case it only
    >>>>>> becomes a null pointer constant when converted to a pointer; in
    >>>>>> other contexts, it's simply an integer.
    >>>>>
    >>>>> 0 is a null pointer constant. That's all, no context.
    >>>>>
    >>>>> N869
    >>>>> 6.3.2.3 Pointers
    >>>>> [#3] An integer constant expression with the value 0, or
    >>>>> such an expression cast to type void *, is called a null
    >>>>> pointer constant.
    >>>>
    >>>> It is also an integer constant or 6.3.2.3 would not apply. It is
    >>>> clearly both at the same time so why do you seem to be suggesting that
    >>>> context does not matter?
    >>>
    >>> Yes, 0 is both an integer constant and a null pointer constant. I
    >>> think pete's point (which I agree with) is that 0 is a null pointer
    >>> constant (or at least is "called" a null pointer constant) regardless
    >>> of the context in which it appears. The 0 in:
    >>> int x = 0;
    >>> is by definition a null pointer constant, even though it's not
    >>> converted to a pointer type.

    >>
    >> Never was I so confused.

    >
    > Yes, there is still some confusion.
    >
    >> I now discover
    >>
    >> char *p = 0; /* is the preferred way to create a null pointer +/

    >
    > not everyone prefers it, but some do.
    >
    >> And since 0 converts to false in a boolean expression then
    >>
    >> if(p){
    >> }
    >>
    >> is perfectly valid

    >
    > This is valid but not because of 0 converting to false in a boolean
    > expression. At least, that phrase has enough vague parts to it that
    > it is not clear what you mean.
    >
    > In the "if" you wrote p is not converted. An 'if' is defined in terms
    > of the expression comparing equal (or not equal) to 0. When a pointer
    > is compared to 0 it is the 0 that gets converted to a null pointer.
    > This is why the test is safe and correct even when a null pointer has
    > a representation that is not all bit zero.
    >
    >> and the NULL check is completely irrelevant since the
    >> internal representation does not come into it.

    >
    > I can't follow this at all. The internal representation is what
    > determines (sometimes rather obliquely) the value of p so it does come
    > into it. What matters is whether p compares equal to a null pointer
    > of the same type.
    >
    > What do you mean by the NULL check? It is guaranteed that given char *p:
    >
    > if (p)
    > if (p == 0)
    > if (p == NULL)
    >
    > are all the same.


    They are? :-; I don't think so but I know what you meant.

    >
    >> The 0 value is all that matters.

    >
    > It is whether the pointer is or is not a null pointer that matters. I
    > am not sure if that is what you mean by "the 0 value". 0 is both a
    > pointer value and an integer value and C can't compare these two
    > without converting one or the other. Everything is designed to work
    > if the conversion goes one way:
    >
    > if (p) => if (p == 0) => 0 converts to a null pointer
    >
    > but it may not work if you force the conversion the wrong way:
    >
    > if ((int)p) => if ((int)p == 0) => 0 taken to be an int
    >
    > what happens here is implementation defined and a null pointer may not
    > convert to (int)0.


    I'll clarify - its irrelevant compared to some doctrine because you
    simply do not need the check. When you assign 0 to p it is NULL. And the
    small core that have said here in the past that you SHOULD compare to NULL
    were not correct.

    e.g

    if(p=malloc(X)){
    /* is perfectly sound and what I have done for years */
    }
    Richard, Feb 9, 2009
    #9
  10. In article <gmp1h7$k46$>,
    Richard <> wrote:
    ....
    >I have run large C projects. And the core clique would not be allowed 10
    >miles from any of them. Especially Falconer. Can you image them rubbing
    >their beards in technical meetings and acting all confused as someone
    >sketches out a program flow and says "we pass a reference to the huge
    >data block here" ....


    Indeed. Quite.

    "He who can, does. He who can't, teaches. He who can't teach, becomes
    a CLC reg."
    Kenny McCormack, Feb 9, 2009
    #10
  11. Stephen Sprunk

    Richard Guest

    (Kenny McCormack) writes:

    > In article <gmp1h7$k46$>,
    > Richard <> wrote:
    > ...
    >>I have run large C projects. And the core clique would not be allowed 10
    >>miles from any of them. Especially Falconer. Can you image them rubbing
    >>their beards in technical meetings and acting all confused as someone
    >>sketches out a program flow and says "we pass a reference to the huge
    >>data block here" ....

    >
    > Indeed. Quite.
    >
    > "He who can, does. He who can't, teaches. He who can't teach, becomes
    > a CLC reg."


    Actually that old adage is false. At least in my experience. The best
    "team players" and coders in the teams I have been involve in were
    invariably also the best teachers. Communication makes a good team. Good
    programmers communicate in all sorts of ways not least their coding
    style - a common language for all. They types could also stand in front
    of an audience and explain WHY it was done as it was. In other words
    those who can, can ALSO teach.

    But teachers not involved in real projects in the real world? Yeah,
    pretty much useless anal retentive bullies. Oh. I see!
    Richard, Feb 9, 2009
    #11
  12. Stephen Sprunk

    Richard Guest

    "Lorenzo Villari" <> writes:

    > "Richard" <> ha scritto nel messaggio
    > news:gmp83i$58d$...
    >>
    >> But teachers not involved in real projects in the real world? Yeah,
    >> pretty much useless anal retentive bullies. Oh. I see!
    >>

    >
    > May I ask which real project are you involved? I'm not polemic, just
    > curious. Of course if this is too personal I understand...


    Various. From GUI layers to high performance game engines to run of the
    mill collating and reporting of live terminal data. Lots of different
    things.

    But one thing was common : any jobsworths made it hell.

    But lets make something clear hear : someone who knows ths standard and
    can advise, pragmatically, on its use is more than welcome.

    People who profess not to understand when we say a pointer has a value
    or that a parameter holds a reference need not apply.
    Richard, Feb 9, 2009
    #12
  13. Richard <> writes:

    <snip>
    > I'll clarify - its irrelevant compared to some doctrine because you
    > simply do not need the check. When you assign 0 to p it is NULL. And the
    > small core that have said here in the past that you SHOULD compare to NULL
    > were not correct.


    I am not sure who they are. Surely any such post was quickly corrected?

    --
    Ben.
    Ben Bacarisse, Feb 9, 2009
    #13
  14. Richard Heathfield <> writes:

    > said:
    >
    > <snip>
    >
    >> [...] I believe (meaning I can' remember where I read it)
    >> that this is problematic
    >>
    >> assert (p);
    >>
    >> that it needs to be replaced with
    >>
    >> assert (p != 0);
    >>
    >> to be safe

    >
    > Yes, that's required in C90 because assert requires an integer
    > expression (specifically, a value of type int).


    Chapter and verse, please? I didn't see this requirement in my version
    of the standard.

    The only thing I can imagine going wrong is if <assert.h> contained
    something like

    #ifndef NDEBUG
    extern _assert();
    #define assert(x) _assert(x, #x, __FILE__, __LINE__)
    #else
    #define assert(x) ((void)0)
    #endif

    But if `assert(x)' expands to a statement which passes `x' to a function
    for which a prototype is in scope, all will be well, and it's a little
    hard to imagine that the C90 committee put in a loophole to allow
    implementors to avoid using prototypes. And the description of the
    macro as

    void assert(int expression);

    suggests to me that it should behave as if it were a function declared
    with that prototype.

    I would be willing to believe that pre-C90 implementations had the
    "integer expression" requirement.
    Nate Eldredge, Feb 9, 2009
    #14
  15. Nate Eldredge <> writes:
    > Richard Heathfield <> writes:
    >
    >> said:
    >>
    >> <snip>
    >>
    >>> [...] I believe (meaning I can' remember where I read it)
    >>> that this is problematic
    >>>
    >>> assert (p);
    >>>
    >>> that it needs to be replaced with
    >>>
    >>> assert (p != 0);
    >>>
    >>> to be safe

    >>
    >> Yes, that's required in C90 because assert requires an integer
    >> expression (specifically, a value of type int).

    >
    > Chapter and verse, please? I didn't see this requirement in my version
    > of the standard.


    There's not a specific requirement, but the C90 definition of assert
    is a bit iffy (which is why it was fixed in C99). The C90 standard
    says that assert is a macro, but it shows a prototype as if it were a
    function:

    #include <assert.h>
    void assert(int expression);

    > The only thing I can imagine going wrong is if <assert.h> contained
    > something like


    [snip]
    > And the description of the macro as
    >
    > void assert(int expression);
    >
    > suggests to me that it should behave as if it were a function declared
    > with that prototype.


    I'm sure it was intended to suggest that, but it doesn't actually say
    so. Macro arguments aren't checked for type or implicitly converted
    the way function arguments are. And since the standard doesn't say
    how assert() is implemented, it doesn't define the behavior when you
    pass it an argument of a type other than int.

    And if NDEBUG is defined, we know that assert("not an integer")
    expands to ((void)0), which doesn't violate any constraint; if assert
    were a function, that call would be a constraint violation.

    > I would be willing to believe that pre-C90 implementations had the
    > "integer expression" requirement.


    I'd be willing to believe that most, or perhaps even all, C90
    implementations work just fine with assert() with any scalar argument.
    The C90 standard just didn't require them to do so.

    See also the C99 rationale
    <http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf>,
    section 7.2.1.1:

    Some pre-C89 implementations tolerated any arbitrary scalar
    expression as the argument to the assert macro, but the C89
    Committee decided to require correct operation only for int
    expressions. C99, on the other hand, permits arbitrary scalar
    expressions.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 9, 2009
    #15
  16. In article <>, Nate Eldredge <> wrote:

    >> Yes, that's required in C90 because assert requires an integer
    >> expression (specifically, a value of type int).


    >Chapter and verse, please? I didn't see this requirement in my version
    >of the standard.


    The synopsis in 7.2.1.1 is

    void assert(int expression);

    I haven't encountered a system where assert(pointer) didn't work, and
    now that it's allowed in C99 I wouldn't bother fixing it. Even if C99
    as a whole is not widely implemented, any system that even makes a nod
    towards C99 will get this right.

    -- Richard
    --
    Please remember to mention me / in tapes you leave behind.
    Richard Tobin, Feb 9, 2009
    #16
  17. Golden California Girls <> writes:
    [...]
    > The issue is in the wording of the standard. There is no question
    > that a "0" in the source code is either an arithmetic zero or a null
    > pointer constant.


    It's both. The token 0 is always an integer constant of type int with
    the value zero, and it's always a null pointer constant, regardless of
    the context. The fact that it's a null pointer constant means that it
    can be converted to a pointer type, but it doesn't have to be.

    There's no great significance to the fact that the 0 in
    int x = 0;
    is a null pointer constant; it was just easier to define it that way.

    > However it is not clear that a "0" in the English
    > language of the standards document is also both. I believe it is a
    > safe assumption your example works, and I think that is what the
    > standards writers want, but their wording doesn't say that. They
    > explicitly say that a comparison (pointer != 0) that the zero be
    > treated as a null pointer constant, but make no such statement for if
    > (pointer).
    > The place where the comparison of a pointer and zero also being the
    > null pointer constant is defined explicitly uses comparison operators
    > in the source language. The place where if (pointer) is defined uses
    > English. Ambiguity.


    I'm willing to assume that the English phrase "if the expression
    compares unequal to 0" in the standard's description of the if
    statement (and similar wording for while et al) refers to the
    equvalent of ``... != 0'' in C. Implementers and programmers have
    universally (apart from a couple of discussions in this newsgroup)
    made that assumption. I can't think of another interpretation that
    makes sense, and at least in this instance I'm willing to base my
    interpretation at least partly on the assumption that it makes sense.

    Clearly this:

    int *ptr = NULL;
    if (ptr) { /* ... */ }

    is valid. As far as I can tell, it can have no coherent meaning
    consistent with the wording of the standard unless "compares unequal
    to 0" means ``ptr != 0'', where 0 is a null pointer constant
    implicitly converted to a null pointer value of type int*.

    I think we agree that this is the intent. The question is whether the
    standard's wording expresses that intent sufficiently clearly. In my
    opinion, it does. If you think it doesn't, feel free to bring it up
    in comp.std.c; that newsgroup has no official relationship to the
    standard committee, but a number of members do read it.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 9, 2009
    #17
  18. Golden California Girls <> writes:

    > Richard wrote:
    >> I'll clarify - its irrelevant compared to some doctrine because you
    >> simply do not need the check. When you assign 0 to p it is NULL. And the
    >> small core that have said here in the past that you SHOULD compare to NULL
    >> were not correct.
    >>
    >> e.g
    >>
    >> if(p=malloc(X)){
    >> /* is perfectly sound and what I have done for years */
    >> }

    >
    > The issue is in the wording of the standard. There is no question
    > that a "0" in the source code is either an arithmetic zero or a null
    > pointer constant.


    Not quite: it is both at the same time. And whilst in normal use this
    distinction does not matter much it does if you are going to go on to
    claim a hole in the standard:

    > However it is not clear that a "0" in the English language of the
    > standards document is also both.


    It is, to me, totally unambiguous that is must be both. Note for
    example that in description of "if" the standard does not say "the
    expression compares equal to zero". It says 0. This is because the
    comparison is to be take as if it were "== 0".

    > I believe it is a safe assumption
    > your example works, and I think that is what the standards writers
    > want, but their wording doesn't say that. They explicitly say that
    > a comparison (pointer != 0) that the zero be treated as a null
    > pointer constant, but make no such statement for if (pointer).


    I can put no other meaning to "compares equal to 0" other than to take
    0 as if it were C, not English. Why write "0" in English? Zero would
    be normal way to write it if no technical meaning is intended.

    > The
    > place where the comparison of a pointer and zero also being the null
    > pointer constant is defined explicitly uses comparison operators in
    > the source language. The place where if (pointer) is defined uses
    > English. Ambiguity.


    Only if you are searching very hard for an ambiguity. 0 is a null
    pointer constant and to suggest that the standard uses 0 in some way
    that is not to be interpreted as a NPC seems like deliberate
    obfuscation!

    --
    Ben.
    Ben Bacarisse, Feb 9, 2009
    #18
  19. Stephen Sprunk

    Kaz Kylheku Guest

    On 2009-02-09, Keith Thompson <> wrote:
    > There's not a specific requirement, but the C90 definition of assert
    > is a bit iffy (which is why it was fixed in C99). The C90 standard
    > says that assert is a macro, but it shows a prototype as if it were a
    > function:
    >
    > #include <assert.h>
    > void assert(int expression);


    So what? Many library functions could be macros.

    There are obvious ways of implementing assert which break on a pointer
    argument:

    void __assert_function(int, const char *, const char *, int);
    #define assert(expr) __assert_function((expr), #expr, __FILE__, __LINE__)

    The above could fixed by (expr) != 0, but it's C90 conforming, and you can't
    just go into your compiler headers and fix them.

    Nothing iffy about this. For maximum portability, do not pass a pointer to
    assert in the C90 dialect.

    Yes, a prototype is a specific requirement. The abstract prototype may be
    backed by an actual prototype (perhaps with more parameters) like that of
    __assert_function above.
    Kaz Kylheku, Feb 9, 2009
    #19
  20. Kaz Kylheku <> writes:
    > On 2009-02-09, Keith Thompson <> wrote:
    >> There's not a specific requirement, but the C90 definition of assert
    >> is a bit iffy (which is why it was fixed in C99). The C90 standard
    >> says that assert is a macro, but it shows a prototype as if it were a
    >> function:
    >>
    >> #include <assert.h>
    >> void assert(int expression);

    >
    > So what? Many library functions could be macros.


    But assert is unique, or nearly so, in that it's specifically required
    to be a macro.

    > There are obvious ways of implementing assert which break on a pointer
    > argument:
    >
    > void __assert_function(int, const char *, const char *, int);
    > #define assert(expr) __assert_function((expr), #expr, __FILE__, __LINE__)
    >
    > The above could fixed by (expr) != 0, but it's C90 conforming, and you can't
    > just go into your compiler headers and fix them.
    >
    > Nothing iffy about this. For maximum portability, do not pass a pointer to
    > assert in the C90 dialect.


    Agreed, but if assert were defined as an ordinary library function
    (with, as always, permission for the implementation to provide a
    function-like macro with the same name), then assert(1.0) would be
    perfectly safe, and assert(ptr) would be a constraint violation. As
    it is (or was, this being C90), the macro that defines assert could
    conceivably pass its argument to a variadic function, causing
    undefined behavior unless the argument is actually of type int. That
    would be unfriendly, but not non-conforming as far as I can tell.

    Unless the prototype shown in the standard, which needn't actually
    exist, is intended to imply that assert actually acts just like a
    function with that prototype. But then you couldn't use a pointer
    argument, as you can in C99.

    For maximum portability, I wouldn't pass anything other than an int
    value to assert. This isn't too difficult; I'd always write
    assert(ptr != NULL);
    rather than
    assert(ptr);
    anyway. (Others prefer greater terseness.)

    > Yes, a prototype is a specific requirement. The abstract prototype may be
    > backed by an actual prototype (perhaps with more parameters) like that of
    > __assert_function above.


    It may be, but it needn't be.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Feb 9, 2009
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    248
    Mark -Mortakai- Moran
    Sep 11, 2008
  2. Antoninus Twink

    Re: Ike Naar

    Antoninus Twink, Feb 8, 2009, in forum: C Programming
    Replies:
    1
    Views:
    302
    Ben Bacarisse
    Feb 8, 2009
  3. Keith Thompson

    Re: Ike Naar

    Keith Thompson, Feb 8, 2009, in forum: C Programming
    Replies:
    5
    Views:
    353
    Richard Bos
    Feb 23, 2009
  4. Replies:
    1
    Views:
    102
    Mark -Mortakai- Moran
    Sep 11, 2008
Loading...

Share This Page