Null constant pointer as argument of no-prototype call

Discussion in 'C Programming' started by Luca Forlizzi, Nov 22, 2010.

  1. Hello,

    today I noticed that passing a null constant pointer as argument to a
    function
    called with no prototype visible, in corrispondence of a pointer
    parameter, is undef.b.
    This is because when no prototype is visible the argument should be
    compatible with
    the parameter, and the "null constant pointer" is really an integer
    expression.
    Is that right?

    If so, isn't there a difference between the case where the null
    constant pointer
    is defined as 0 and the one where it is defined as (void *)0 ? It
    seems to me that
    if the parameter has type void *, in the formed case there is
    unde.b., while in the
    latter the behavior is defined.

    In case what I wrote above is true, are there real implementations
    where it
    does not work ?
    (I imagine that in implementations pre-prototypes, passing a
    null constant pointer does work)

    Luca Forlizzi
     
    Luca Forlizzi, Nov 22, 2010
    #1
    1. Advertising

  2. Luca Forlizzi <> writes:
    > today I noticed that passing a null constant pointer as argument to a
    > function called with no prototype visible, in corrispondence of a
    > pointer parameter, is undef.b. This is because when no prototype is
    > visible the argument should be compatible with the parameter, and the
    > "null constant pointer" is really an integer expression. Is that
    > right?


    "undef.b" means "undefined behavior, right?

    And it's "null pointer constant", not "null constant pointer".

    A null pointer constant is either an integer constant expression
    with the value 0, or such an expression cast to void*. Its type
    can be any integer type or void*, but it's most commonly either
    int or void*.

    If you're calling a function with no visible prototype, the promoted
    type of the argument must match the type of the parameter. Which means,
    for example, that free(NULL) can have undefined behavior if NULL is
    defined as 0.

    The solution is simple: *always* have a visible prototype for any
    function you call.

    This doesn't help for arguments corresponding to the "..." for
    variadic functions; for example, printf("%p\n", NULL) has the same
    problem, even if the prototype is visible. The solution there is to
    cast the argument to the desired type: printf("%p\n", (void*)NULL);

    > If so, isn't there a difference between the case where the null
    > constant pointer is defined as 0 and the one where it is defined as
    > (void *)0 ? It seems to me that if the parameter has type void *, in
    > the formed case there is unde.b., while in the latter the behavior is
    > defined.


    Yes.

    > In case what I wrote above is true, are there real implementations
    > where it does not work ? (I imagine that in implementations
    > pre-prototypes, passing a null constant pointer does work)


    The phrase "does not work" is tricky in the presence of undefined
    behavior. There is no correct behavior, so strictly speaking it
    can neither "work", nor "not work".

    Certainly. If you use 0, which is a null pointer constant, in a
    pointer context (for example, if the implementation has "#define
    NULL 0"), and int and void* are of different sizes, it's likely
    to fail in some arbitrarily bad way, such as passing unexpected
    values or crashing your program. Likewise if integer and pointer
    arguments are passed differently, say in different registers.
    And yes, the same program can appear to "work", or can blow up,
    depending on how the implementation chooses to define NULL.

    So don't do that.

    --
    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, Nov 22, 2010
    #2
    1. Advertising

  3. On 22 Nov, 18:10, Keith Thompson <> wrote:
    > Luca Forlizzi <> writes:


    >
    > "undef.b" means "undefined behavior, right?


    yes

    >
    > And it's "null pointer constant", not "null constant pointer".


    ops... I apologise

    > If you're calling a function with no visible prototype, the promoted
    > type of the argument must match the type of the parameter.  Which means,
    > for example, that free(NULL) can have undefined behavior if NULL is
    > defined as 0.
    >
    > The solution is simple: *always* have a visible prototype for any
    > function you call.


    Agreed, I was not seeing the issue as a problem, and I always use
    prototypes, I was just interested in understanding what the standard
    says. Thanks to your explanations, I have a better understanding, now.

    > This doesn't help for arguments corresponding to the "..." for
    > variadic functions; for example, printf("%p\n", NULL) has the same
    > problem, even if the prototype is visible.  The solution there is to
    > cast the argument to the desired type: printf("%p\n", (void*)NULL);


    so, this means that one can not use %p to print the value of
    a pointer to a function, right?


    > The phrase "does not work" is tricky in the presence of undefined
    > behavior.  There is no correct behavior, so strictly speaking it
    > can neither "work", nor "not work".


    Yes I knew that, I meant to say "does not work as if a correct
    prototype for the called function were visible". Sorry for being
    sloppy.


    > And yes, the same program can appear to "work", or can blow up,
    > depending on how the implementation chooses to define NULL.
    >
    > So don't do that.


    I won't. But the information you give me, might be useful to know to
    find elusive bugs. Thanks, Keith
     
    Luca Forlizzi, Nov 23, 2010
    #3
  4. Luca Forlizzi <> writes:
    > On 22 Nov, 18:10, Keith Thompson <> wrote:

    [...]
    >> This doesn't help for arguments corresponding to the "..." for
    >> variadic functions; for example, printf("%p\n", NULL) has the same
    >> problem, even if the prototype is visible.  The solution there is to
    >> cast the argument to the desired type: printf("%p\n", (void*)NULL);

    >
    > so, this means that one can not use %p to print the value of
    > a pointer to a function, right?


    Indirectly, yes. You can write:
    printf("%p\n", (void*)func_ptr);
    and it doesn't violate any constraint as far as I can tell, but
    the standard doesn't define the behavior of a conversion from a
    pointer-to-function type to void*.

    I note that one popular compiler produces a warning when invoked
    in conforming mode:

    warning: ISO C forbids conversion of function pointer to object pointer type

    I believe this warning is incorrect.

    (The cast is likely to work as expected on many implementations.)

    [...]

    --
    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, Nov 23, 2010
    #4
    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. Martin Magnusson
    Replies:
    2
    Views:
    512
    John Harrison
    Oct 8, 2004
  2. June Lee
    Replies:
    2
    Views:
    810
    Jim Cobban
    Apr 13, 2008
  3. aneuryzma
    Replies:
    3
    Views:
    729
    Jim Langston
    Jun 16, 2008
  4. Christopher
    Replies:
    4
    Views:
    448
    Ruben Safir
    Jul 9, 2011
  5. G G
    Replies:
    3
    Views:
    95
    Ben Bacarisse
    Apr 20, 2014
Loading...

Share This Page