• Confused about the implementation of static int isnullptr(Tree e) , any

    From Thimble Liu@21:1/5 to All on Tue Apr 14 06:58:41 2020
    I'm reading the code of lcc, and also the book. And I'm stucking at the function isnullptr(Tree e), in file enode.c. The function is below:

    static int isnullptr(e) Tree e; {
    return (isint(e->type) && generic(e->op) == CNST
    && cast(e, unsignedtype)->u.v.u == 0)
    || (isvoidptr(e->type) && e->op == CNST+P
    && e->u.v.p == NULL);
    }


    I've checked the ANSI C standard about the null pointer and the null pointer constant, and still can't see how the return of isnullptr connect about the standard about null pointer or null pointer constant.

    I also read the code of cast, does (isvoidptr(e->type) && e->op == CNST+P && e->u.v.p == NULL) implies that "a integer constant expression which value is 0 cast to type void *"? If so, why the op->e should be CNSP+P, as the code of lex.c suggested 0 is
    processed into a CNST+I tree? Is it caused by constant folding?

    Really hope to get help! Thanks!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Tue Apr 14 23:50:48 2020
    Le 14/04/2020 à 15:58, Thimble Liu a écrit :
    I'm reading the code of lcc, and also the book. And I'm stucking at the function isnullptr(Tree e), in file enode.c. The function is below:

    static int isnullptr(e) Tree e; {
    return (isint(e->type) && generic(e->op) == CNST
    && cast(e, unsignedtype)->u.v.u == 0)
    || (isvoidptr(e->type) && e->op == CNST+P
    && e->u.v.p == NULL);
    }


    I've checked the ANSI C standard about the null pointer and the null pointer constant, and still can't see how the return of isnullptr connect about the standard about null pointer or null pointer constant.

    I also read the code of cast, does (isvoidptr(e->type) && e->op == CNST+P && e->u.v.p == NULL) implies that "a integer constant expression which value is 0 cast to type void *"? If so, why the op->e should be CNSP+P, as the code of lex.c suggested 0
    is processed into a CNST+I tree? Is it caused by constant folding?

    Really hope to get help! Thanks!


    There are two arms in the condition above:

    1:

    isint(e->type) &&
    generic(e->op) == CNST &&
    cast(e, unsignedtype)->u.v.u == 0)

    An integer constant of value zero can be used as a null pointer

    2:

    isvoidptr(e->type) &&
    e->op == CNST+P &&
    e->u.v.p == NULL

    A pointer with type constant and value zero

    The zero is read as an integer, yes, but it can be later cast into a
    void pointer or used to return a NULL value.

    for instance

    char *fn(void)
    {
    return 0;
    }


    P.S. There is no constant folding in the original lcc. I added that
    feature much later.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thimble Liu@21:1/5 to jacobnavia on Tue Apr 14 20:05:35 2020
    On Wednesday, April 15, 2020 at 5:50:50 AM UTC+8, jacobnavia wrote:
    Le 14/04/2020 à 15:58, Thimble Liu a écrit :
    I'm reading the code of lcc, and also the book. And I'm stucking at the function isnullptr(Tree e), in file enode.c. The function is below:

    static int isnullptr(e) Tree e; {
    return (isint(e->type) && generic(e->op) == CNST
    && cast(e, unsignedtype)->u.v.u == 0)
    || (isvoidptr(e->type) && e->op == CNST+P
    && e->u.v.p == NULL);
    }


    I've checked the ANSI C standard about the null pointer and the null pointer constant, and still can't see how the return of isnullptr connect about the standard about null pointer or null pointer constant.

    I also read the code of cast, does (isvoidptr(e->type) && e->op == CNST+P && e->u.v.p == NULL) implies that "a integer constant expression which value is 0 cast to type void *"? If so, why the op->e should be CNSP+P, as the code of lex.c suggested 0
    is processed into a CNST+I tree? Is it caused by constant folding?

    Really hope to get help! Thanks!


    There are two arms in the condition above:

    1:

    isint(e->type) &&
    generic(e->op) == CNST &&
    cast(e, unsignedtype)->u.v.u == 0)

    An integer constant of value zero can be used as a null pointer

    2:

    isvoidptr(e->type) &&
    e->op == CNST+P &&
    e->u.v.p == NULL

    A pointer with type constant and value zero

    The zero is read as an integer, yes, but it can be later cast into a
    void pointer or used to return a NULL value.

    for instance

    char *fn(void)
    {
    return 0;
    }


    P.S. There is no constant folding in the original lcc. I added that
    feature much later.

    Thank you very much for reply!
    I understand that a pointer to type constant and value zero is a null pointer, but the second arm of that condition still makes me confused.
    I don't understand how a integer constant 0 cast to void *, can result a tree which op is CNST+P, and u.v.p field equal to NULL.
    I think cast a integer constant 0 to type void * should result a tree that its return type is void * and op is still CNST+I and value field should be integer 0, am I right?

    When I'was readingthe code of cast, I didn't see codes about changing the op of the tree, I think function cast is done by function retype() and simplify(). retype() doesn't change the op of the tree. Is condition 2 due to function simplify()?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Wed Apr 15 15:02:13 2020
    Le 15/04/2020 à 05:05, Thimble Liu a écrit :
    I don't understand how a integer constant 0 cast to void *, can result a tree which op is CNST+P, and u.v.p field equal to NULL.

    I think that if you write:

    char *p = 0x40407865;

    You are making a pointer out of a constant. That wouldn't be the NULL
    pointer since its value would be different from zero, hence the second condition.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to jacobnavia on Wed Apr 15 12:47:51 2020
    jacobnavia <jacob@jacob.remcomp.fr> writes:
    Le 15/04/2020 à 05:05, Thimble Liu a écrit :
    I don't understand how a integer constant 0 cast to void *, can
    result a tree which op is CNST+P, and u.v.p field equal to NULL.

    I think that if you write:

    char *p = 0x40407865;

    You are making a pointer out of a constant. That wouldn't be the NULL
    pointer since its value would be different from zero, hence the second condition.

    Right. Expanding on that a bit, the C standard defines a "null
    pointer constant" as "An integer constant expression with the value
    0, or such an expression cast to type void *". So
    char *p = 0;
    sets p to a null pointer value, and
    char *p = (char*)0x40407865;
    sets p to some implementation-defined value (almost certainly not a null pointer), but
    int zero = 0;
    char *p = (char*)zero;
    doesn't necessarily set p to a null pointer value. It *probably*
    will (and lcc might even guarantee it), but the the language
    doesn't guarantee it, because there is no null pointer constant.
    (Even "const int zero = 0;" wouldn't make `zero` or `(char*)zero`
    a null pointer constant.)

    Note that I'm only talking about what the C standard says. I know
    practically nothing about lcc internals. lcc, I'm fairly sure,
    represents a null pointer as all-bits-zero, which is the case for all
    or almost all actual compilers but is not required by the language.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips Healthcare
    void Void(void) { Void(); } /* The recursive call of the void */

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)