Passing NULL as a function pointer

Discussion in 'C Programming' started by pozz, Feb 17, 2011.

  1. pozz

    pozz Guest

    I have a function that has a function pointer as one of its argument.
    Can I pass NULL as this parameter?

    I have some code (from lwip project - www.sics.se/~adam/lwip) that
    often pass NULL as function pointer parameter, but my compiler (for 16
    bits Fujtsu 16LX series microcontrollers) gives a warning for that.
    For example:
    argument passing incompatible pointer types:
    expected `tcp_accept_fn' actual `void *': argument 2 of
    `tcp_accept'
    pozz, Feb 17, 2011
    #1
    1. Advertising

  2. pozz

    Douglas Guest

    On Thu, 17 Feb 2011, pozz wrote:

    > I have a function that has a function pointer as one of its argument.
    > Can I pass NULL as this parameter?
    > [...]


    Hmm... well, dereferencing a null pointer is undefined behavior.
    So, probably not. Of coarse, OTOH I'm fairly new here.
    Douglas, Feb 17, 2011
    #2
    1. Advertising

  3. pozz

    James Kuyper Guest

    On 02/17/2011 08:50 AM, Douglas wrote:
    > On Thu, 17 Feb 2011, pozz wrote:
    >
    >> I have a function that has a function pointer as one of its argument.
    >> Can I pass NULL as this parameter?
    >> [...]

    >
    > Hmm... well, dereferencing a null pointer is undefined behavior.
    > So, probably not. Of coarse, OTOH I'm fairly new here.


    He didn't say that the pointer would be de-referenced. When part of a
    function's behavior is optional in a way that is connected to one of
    it's pointer parameters, it's fairly commonplace to use a null pointer
    argument of that type to indicate that the optional behavior should be
    skipped.

    --
    James Kuyper
    James Kuyper, Feb 17, 2011
    #3
  4. pozz wrote:

    > ... my compiler (for 16 bits Fujtsu 16LX series microcontrollers) gives a warning for that.
    > For example:
    > argument passing incompatible pointer types:
    > expected `tcp_accept_fn' actual `void *': argument 2 of
    >`tcp_accept'


    In addition to what others wrote, that warning complains about
    incompatible types, not about the pointer being NULL.
    If you want a "clean compile", casting NULL into the type of function
    pointer expected will squelch the warning.

    --
    Roberto Waltman

    [ Please reply to the group.
    Return address is invalid ]
    Roberto Waltman, Feb 17, 2011
    #4
  5. Roberto Waltman <> writes:
    > pozz wrote:
    >> ... my compiler (for 16 bits Fujtsu 16LX series microcontrollers) gives a warning for that.
    >> For example:
    >> argument passing incompatible pointer types:
    >> expected `tcp_accept_fn' actual `void *': argument 2 of
    >>`tcp_accept'

    >
    > In addition to what others wrote, that warning complains about
    > incompatible types, not about the pointer being NULL.
    > If you want a "clean compile", casting NULL into the type of function
    > pointer expected will squelch the warning.


    Yes, that will likely silence the warning -- but keep in mind
    that it's a workaround for a compiler bug. (I don't mean
    a "bug" in the sense that the compiler is necessarily non-conforming,
    just that the warning is spurious.)

    You do generally need to cast NULL to the expected pointer type when
    calling variadic functions, but that's not what's happening here; the
    compiler wouldn't know the expected type.

    A couple of questions for the OP:

    Does the compiler you're using claim to be conforming? If not, what
    does its documentation say about the use of function pointers?

    Since you didn't show us the full source of the program, we can't be
    100% sure of what's going on. What happens when you compile this?

    typedef void (*funcptr)(void);

    void func(funcptr arg)
    {
    if (arg) {
    arg();
    }
    }

    int main(void)
    {
    func((void*)0);
    return 0;
    }

    --
    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 17, 2011
    #5
  6. On Feb 17, 3:18 am, pozz <> wrote:
    > I have a function that has a function pointer as one of its argument.
    > Can I pass NULL as this parameter?
    >
    > I have some code (from lwip project -www.sics.se/~adam/lwip) that
    > often pass NULL as function pointer parameter, but my compiler (for 16
    > bits Fujtsu 16LX series microcontrollers) gives a warning for that.
    > For example:
    >   argument passing incompatible pointer types:
    >     expected `tcp_accept_fn' actual `void *': argument 2 of
    > `tcp_accept'


    Of course, if a few CPU cycles won't kill you, it's always better to
    pass a pointer to properly shaped function that does nothing.
    Michael Angelo Ravera, Feb 17, 2011
    #6
  7. Michael Angelo Ravera <> writes:
    > On Feb 17, 3:18 am, pozz <> wrote:
    >> I have a function that has a function pointer as one of its argument.
    >> Can I pass NULL as this parameter?
    >>
    >> I have some code (from lwip project -www.sics.se/~adam/lwip) that
    >> often pass NULL as function pointer parameter, but my compiler (for 16
    >> bits Fujtsu 16LX series microcontrollers) gives a warning for that.
    >> For example:
    >>   argument passing incompatible pointer types:
    >>     expected `tcp_accept_fn' actual `void *': argument 2 of
    >> `tcp_accept'

    >
    > Of course, if a few CPU cycles won't kill you, it's always better to
    > pass a pointer to properly shaped function that does nothing.


    Why is that always better? If the function is specified to do nothing
    if the passed function pointer is null, what's wrong with passing a null
    pointer (assuming the compiler doesn't issue a spurious diagnostic)?

    --
    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 17, 2011
    #7
  8. pozz

    pozz Guest

    On 17 Feb, 17:39, Keith Thompson <> wrote:
    > Yes, that will likely silence the warning -- but keep in mind
    > that it's a workaround for a compiler bug.  (I don't mean
    > a "bug" in the sense that the compiler is necessarily non-conforming,
    > just that the warning is spurious.)


    Yes, I think I'll use this workaround, just to silence this warning.


    > Does the compiler you're using claim to be conforming?  If not, what
    > does its documentation say about the use of function pointers?


    Nothing special.


    > Since you didn't show us the full source of the program, we can't be
    > 100% sure of what's going on.  What happens when you compile this?
    > [...]


    The warning comes again out...
    pozz, Feb 18, 2011
    #8
  9. "pozz" <> wrote:
    On 17 Feb, 17:39, Keith Thompson <> wrote:
    > > Since you didn't show us the full source of the program, we can't be
    > > 100% sure of what's going on. What happens when you compile this?
    > > [...]

    >
    > The warning comes again out...


    That seems to be non-standard behavior.

    What happens if you compile Keith’s example program, but with the line
    func((void*)0);
    replaced with
    func(0);
    — does that work better?

    According to the standard (§6.3.2.3 p3), the following holds:

    int main(void)
    {
    func(0); // should work
    func((void*)0); // should also work, but your system is non-standard
    func(NULL); // resolves to either of the foregoing; should work
    void *null = 0;
    func(null); // should *not* work
    func((funcptr)null); // often permitted (common extension §J.5.7),
    // but not portable, nor guaranteed to work as
    // expected even if it compiles
    return 0;
    }

    Both “0†and “(void*)0†are “null pointer constants†and *should* convert to
    null pointers or null function pointers as required. You might need to override
    your system’s definition of NULL from “(void*)0†to “0†to compensate for its
    non-standard behavior. Probably a better idea than introducing casts all over.

    —Joel
    Joel C. Salomon, Feb 18, 2011
    #9
  10. "Joel C. Salomon" <> writes:
    > "pozz" <> wrote:
    > On 17 Feb, 17:39, Keith Thompson <> wrote:
    >> > Since you didn't show us the full source of the program, we can't be
    >> > 100% sure of what's going on. What happens when you compile this?
    >> > [...]

    >>
    >> The warning comes again out...

    >
    > That seems to be non-standard behavior.


    It doesn't *violate* the standard. Compilers can issue any additional
    warnings they like. They just have to generate correctly working code
    for programs that don't violate any syntax rules or constraints, issue
    diagnostics for any violations of any syntax rules or constraints, and
    refuse to compile anything with an active #error directive.

    The warning about a valid construct does make me worry a little about
    whether the compiler is generating correct code for it, though.

    --
    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 18, 2011
    #10
  11. On 2/17/2011 3:18 AM, pozz wrote:
    > I have a function that has a function pointer as one of its argument.
    > Can I pass NULL as this parameter?
    >
    > I have some code (from lwip project - www.sics.se/~adam/lwip) that
    > often pass NULL as function pointer parameter, but my compiler (for 16
    > bits Fujtsu 16LX series microcontrollers) gives a warning for that.
    > For example:
    > argument passing incompatible pointer types:
    > expected `tcp_accept_fn' actual `void *': argument 2 of
    > `tcp_accept'


    Apparently on your platform NULL is defined as `(void *) 0` or something
    similar (key part being the `void *` type). It is perfectly valid to use
    NULL declared this way for initializing function pointers, but lower
    quality compilers might not be smart enough the realize that. Hence the
    warning.

    You can avoid the warning by passing `0` instead of NULL.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Feb 18, 2011
    #11
  12. pozz <> writes:
    > Il 18/02/2011 20:19, Andrey Tarasevich ha scritto:
    >> Apparently on your platform NULL is defined as `(void *) 0` or something
    >> similar (key part being the `void *` type). It is perfectly valid to use
    >> NULL declared this way for initializing function pointers, but lower
    >> quality compilers might not be smart enough the realize that. Hence the
    >> warning.
    >>
    >> You can avoid the warning by passing `0` instead of NULL.

    >
    > Yes, indeed in the past I passed '0' instead of NULL for function
    > pointers argument, but I don't like this approach anymore...


    Just to avoid any possible misunderstanding, we're talking about
    0
    an integer constant, not
    '0'
    a character constant.

    --
    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 19, 2011
    #12
  13. pozz <> writes:
    > Il 18/02/2011 17:02, Joel C. Salomon ha scritto:
    >> What happens if you compile Keith’s example program, but with the line
    >> func((void*)0);
    >> replaced with
    >> func(0);
    >> — does that work better?

    >
    > Yes, in this way the compiler compiles without any warning.


    So the compiler recognizes 0, but not (void*)0, as a null pointer
    constant.

    Can you submit a bug report? Again, the behavior you've told us
    about isn't necessarily non-conforming, but I am concerned that,
    if the compiler warns about this valid code, it might be handling
    it incorrectly. And even if that's not the case, the warning is
    spurious.

    >> You might need to override
    >> your system’s definition of NULL from “(void*)0†to “0†to compensate
    >> for its
    >> non-standard behavior. Probably a better idea than introducing casts all
    >> over.

    >
    > Yes, it is another good idea, thank you for your suggestion.


    Overriding declarations in your implementations standard headers
    strikes me as a very risky thing to do, unless you have a *very*
    good reason to do so *and* you're rightly confident that you know
    the situation better than the implementers do.

    --
    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 19, 2011
    #13
  14. pozz

    Richard Guest


    >Apparently on your platform NULL is defined as `(void *) 0` or something
    >similar (key part being the `void *` type). It is perfectly valid to use
    >NULL declared this way for initializing function pointers, but lower
    >quality compilers might not be smart enough the realize that. Hence the
    >warning.
    >
    >You can avoid the warning by passing `0` instead of NULL.


    I have not seen a compiler that did not have the NULL value set to
    zero (Not confusing nul and NULL) or a cast as a pointer.

    My understanding of NULL is that it is pointer value that will never
    be in the addressing range of your program. The NULL value is up to
    the compiler (and may be dictated by the hardware). There is no
    guarantee that NULL will be a cast of any particular value.

    Other C compilers could use 0xffffffff as NULL rather than 0. Using a
    numeric value could break code on other compilers.
    Richard, Feb 19, 2011
    #14
  15. Richard <> writes:

    > the compiler (and may be dictated by the hardware). There is no
    > guarantee that NULL will be a cast of any particular value.


    I'm pretty certain that whatever bit pattern the implementation uses
    as representation for NULL, it will have to be equal to (void *) 0. I
    don't have the standard handy, and I cannot remeber if it's
    assignment, comparision or both that's mentioned.

    --
    /Wegge

    Leder efter redundant peering af dk.*,linux.debian.*
    Anders Wegge Keller, Feb 19, 2011
    #15
  16. pozz

    Eric Sosman Guest

    On 2/19/2011 2:17 PM, Richard wrote:
    >
    >> Apparently on your platform NULL is defined as `(void *) 0` or something
    >> similar (key part being the `void *` type). It is perfectly valid to use
    >> NULL declared this way for initializing function pointers, but lower
    >> quality compilers might not be smart enough the realize that. Hence the
    >> warning.
    >>
    >> You can avoid the warning by passing `0` instead of NULL.

    >
    > I have not seen a compiler that did not have the NULL value set to
    > zero (Not confusing nul and NULL) or a cast as a pointer.
    >
    > My understanding of NULL is that it is pointer value that will never
    > be in the addressing range of your program. The NULL value is up to
    > the compiler (and may be dictated by the hardware). There is no
    > guarantee that NULL will be a cast of any particular value.
    >
    > Other C compilers could use 0xffffffff as NULL rather than 0. Using a
    > numeric value could break code on other compilers.


    You're mixing up two or maybe three different things: The run-
    time value of a null pointer, the representation of that value as
    a batch of bytes, and the source-code construct that produces it.
    In an attempt to dispel some confusion:

    - `NULL' is an identifier, a source-code construct. Various
    Standard headers define the name as a macro, also a source-
    code construct.

    - The `NULL' macro defined by the Standard headers expands to
    a "null pointer constant," which is "an integer constant
    expression with the value 0, or such an expression cast to
    type void *". Expressions, constant expressions, and casts
    are also source-code constructs.

    - (Why do I keep harping on "source-code construct?" Because of
    the confusion between the way a value is "spelled" in source
    code and the way that value "actually looks" at run-time. When
    you write '\n' in source, do you imagine that the corresponding
    run-time value involves two quote marks, a back-slash, and an n?
    Just so with 0 or (void*)0: They are the source code's way of
    denoting a value, not images of the value.

    - Onward: When they appear in pointer contexts, 0 and (void*)0
    create null pointer values in the run-time program (but see
    below). These values have unspecified bit patterns (plural
    intended), at the implementation's whim. Many implementations
    use all-bits-zero-for-however-many-bytes-it-requires as a null
    pointer value, but this is not obligatory; the FAQ mentions
    some systems that use(d) other representations.

    - Even when a null pointer constant appears in the source code,
    it is not guaranteed that a null pointer value appears in the
    run-time program. For example, `if (p == NULL) return;' might
    produce code like `ld r0,p; tst r0; jz return_point;' -- and
    where in this code is there a bit pattern representing a null
    pointer value?

    - Finally, to the null pointer value itself. No matter how it
    is represented in the machine, we know (1) all null pointer
    values compare equal to each other, and (2) all null pointer
    values compare *un*equal to pointers to any variable or function
    or allocated memory area. We need not (and should not) appeal
    to notions of an "addressing range" to explain how this is made
    to work; as C programmers all we need to know (and all we should
    rely on) is that it *does* work, somehow. An implementor, of
    course, has the burden of making it work and thus must care about
    the chosen mechanisms, just as he must care about how `static'
    variables get their initial values. As programmers, we should
    fret about the former only as much as we do about the latter.

    If this seems pedantic, that's only because it *is* pedantic.
    But there's so much confusion about null pointers -- the FAQ devotes
    an entire section to the topic -- that perhaps a small helping of
    pedantry is called for.

    --
    Eric Sosman
    lid
    Eric Sosman, Feb 19, 2011
    #16
  17. pozz

    James Kuyper Guest

    On 02/19/2011 02:43 PM, Anders Wegge Keller wrote:
    > Richard<> writes:
    >
    >> the compiler (and may be dictated by the hardware). There is no
    >> guarantee that NULL will be a cast of any particular value.

    >
    > I'm pretty certain that whatever bit pattern the implementation uses
    > as representation for NULL, it will have to be equal to (void *) 0. I
    > don't have the standard handy, and I cannot remeber if it's
    > assignment, comparision or both that's mentioned.


    "be equal to" inherently implies comparison, not assignment.

    (void*)0 is a null pointer constant. The expansion of the NULL macro is
    also required to be one. Since (void*)0 is an expression with a null
    pointer value, in the expression:

    NULL==(void*)0

    whatever expression NULL expands to will also be converted to a null
    pointer value with type 'void*', whether or not NULL itself has a
    pointer type. All null pointers of the same type must compare equal. So,
    yes it is guaranteed.
    --
    James Kuyper
    James Kuyper, Feb 19, 2011
    #17
  18. pozz

    Richard Guest

    On Sat, 19 Feb 2011 20:43:20 +0100, Anders Wegge Keller
    <> wrote:

    >Richard <> writes:
    >
    >> the compiler (and may be dictated by the hardware). There is no
    >> guarantee that NULL will be a cast of any particular value.

    >
    > I'm pretty certain that whatever bit pattern the implementation uses
    >as representation for NULL, it will have to be equal to (void *) 0. I
    >don't have the standard handy, and I cannot remeber if it's
    >assignment, comparision or both that's mentioned.



    Thanks Anders, James and Eric

    My (miss)understanding of this is rather old and goes back to
    something I read that made sense at the time.

    What you have said and http://www.lysator.liu.se/c/c-faq/c-1.html have
    made me change my mind.


    Now the question is. If you want to get at memory address 0, how do
    you? It looks like you cannot. I do not suppose I ever will need to do
    that and if I did there is always assembler.
    Richard, Feb 19, 2011
    #18
  19. Richard <> writes:

    > On Sat, 19 Feb 2011 20:43:20 +0100, Anders Wegge Keller
    > <> wrote:
    >
    >>Richard <> writes:
    >>
    >>> the compiler (and may be dictated by the hardware). There is no
    >>> guarantee that NULL will be a cast of any particular value.

    >>
    >> I'm pretty certain that whatever bit pattern the implementation uses
    >>as representation for NULL, it will have to be equal to (void *) 0. I
    >>don't have the standard handy, and I cannot remeber if it's
    >>assignment, comparision or both that's mentioned.

    >
    >
    > Thanks Anders, James and Eric
    >
    > My (miss)understanding of this is rather old and goes back to
    > something I read that made sense at the time.
    >
    > What you have said and http://www.lysator.liu.se/c/c-faq/c-1.html have
    > made me change my mind.
    >
    >
    > Now the question is. If you want to get at memory address 0, how do
    > you? It looks like you cannot.


    No, it's easy (provided it is permitted by the implementation, of
    course). You can't use (void *)0 because that has a special meaning,
    but then you can access anything using a void pointer anyway. The key
    is to start off with the right type of pointer for whatever you expect
    to find at the zero address:

    char *raw_mem = (char *)0;
    int *descriptors = (int *)0;
    struct interrupt *ivec = (struct interrupt *)0;

    Note that you can't omit the casts or you will run into the problem
    you'd identified.

    <snip>
    --
    Ben.
    Ben Bacarisse, Feb 19, 2011
    #19
  20. On 02/19/2011 06:31 PM, Ben Bacarisse wrote:
    > Richard <> writes:
    >> Now the question is. If you want to get at memory address 0, how do
    >> you? It looks like you cannot.

    >
    > No, it's easy (provided it is permitted by the implementation, of
    > course). You can't use (void *)0 because that has a special meaning,
    > but then you can access anything using a void pointer anyway. The key
    > is to start off with the right type of pointer for whatever you expect
    > to find at the zero address:
    >
    > char *raw_mem = (char *)0;
    > int *descriptors = (int *)0;
    > struct interrupt *ivec = (struct interrupt *)0;
    >
    > Note that you can't omit the casts or you will run into the problem
    > you'd identified.


    Not quite: Assume an architecture where all-zero-bits is a legitimate
    memory address, but all-one-bits is a trap location & therefore the
    choice for the null pointer. This below is technically undefined, but
    it a likely result:

    union foo_ptr {
    foo *p;
    uintptr_t i;
    } ptr;

    ptr.p = (foo *)0;
    assert (ptr.i = ~( (uintptr_t)0 ));

    ptr.i = 0;
    assert (ptr.p != NULL);

    What’s happening is that ‘0’ (and equally, ‘(void *)0’) is what the
    Standard calls a “null pointer constantâ€; when it converted to *any*
    pointer type the result is a null pointer. And on this architecture,
    the null pointer has the all-one-bits representation. If you want a
    pointer to memory address 0, you need to play other games. The union
    trick above might work; also

    char *one = (char *)1;
    void *zero = one - 1;

    might be a slightly more “portable†method.

    —Joel
    Joel C. Salomon, Feb 20, 2011
    #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:
    5
    Views:
    26,498
    Mike Schilling
    Mar 29, 2006
  2. jimjim
    Replies:
    16
    Views:
    822
    Jordan Abel
    Mar 28, 2006
  3. Vijai Kalyan
    Replies:
    4
    Views:
    690
    Vijai Kalyan
    Nov 8, 2005
  4. aneuryzma
    Replies:
    3
    Views:
    692
    Jim Langston
    Jun 16, 2008
  5. Christopher
    Replies:
    4
    Views:
    428
    Ruben Safir
    Jul 9, 2011
Loading...

Share This Page