This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

C51: Null function pointer

I am trying to convert an unmaintainable user interface
driver over to something that uses data structures to define
the menu organization (This example is stripped down to the
bare minimum from my actual app).

Picture an array of screens, selectable by the user's
activation of some arrow keys:

         Col 0                  Col 1
           +-----------+
    Row 0  | Screen 1a |
           +-----------+
                /\ 
                ||
                \/
           +-----------+       +-----------+
    Row 1  | Screen 2a | <===> | Screen 2b |
           +-----------+       +-----------+

I define a function to output each screen (in the code
below, they also change the row & column indices):

  void f1a(void) {

    outputScreen1a();
    if(r > 0)
      r++;
    return;
  }

  /* ============= */

  void f2a(void) {

    outputScreen2a();
    if(c < 1)
      c++;
    return;
  }

  /* ============= */

  void f2b(void) {

    outputScreen2b();
    r = c = 0;
    return;
  }

These are called by the main() function, using a function
pointer table:

  static code const void (* code menuFunc[2][2])(void) = {
    { f1a,    NULL },
    { f2a,    f2b  }
  };

  unsigned char r, c;

  void main(void) {
    unsigned char i;

    SFRPAGE = 0;   /* Go to default page     */
    WDTCN = 0xDE;  /* Disable watchdog timer */
    WDTCN = 0xAD;
    IE   = 0;      /* Disable all interrupts */
    i = 0;
    r = c = 0;

    while (1) {

      if(i < 70) {
        i++;
      } else {
        i = 0;
                  (*menuFunc[r][c])();
      }
    }  /* END while (TRUE) */

  }  /* END main() */

As presented above, the source file will compile without
error. But my application is quite a bit more complex than
what I present here, the table is assymetrical (marked by
the NULL pointer) and I want to guantee I do not
inadvertently dereference it, so I add a qualification to
the main control loop:

      while (1) {

        if(i < 70) {
          i++;
        } else {
          i = 0;
          if((menuFunc[r][c])() != NULL)
                    (*menuFunc[r][c])();
        }
      }  /* END while (TRUE) */

C51 does not like this. It flags the statement where I check
for NULL:

?????.C:(56): error C193: '!=' : illegal conversion from/to 'void'

NULL is defined in stdio.h:

 #define NULL ((void *) 0)

K&R doesn't state it explicitly, but seems to assume that
void is an object type, that (void *) can only point to an
object, and never uses NULL as a pointer to a function.

So the question is, if I can't use NULL to mark an
uncallable function in the table, is there a null function
pointer I could use instead?

============================================================
Gary Lynch           |   To send mail, no$pam in domain name
lynchg@no$pam.com    |   must be changed to stacoenergy.
============================================================

Parents
  • Let's see if I can apply your advice to my logistics.

    My 'top level BOM' is a system containing 5 MCUs, which
    communicate over several networks. Thus I must maintain 5
    execution modules and around 120 source files to make a
    release.

    The product is offered in 50 different configurations which
    I maintain from a common source deck by changing the values
    of 4 pre-processor constants at build time.

    Four of the 5 applications are based on finite state
    machines, which I implement calling a function pointer
    table, indexed by the state variable. When elements of the
    call tree pass strings as parameters to lower-level
    functions, these strings get stored in the same ?CO? code
    segment as the function pointer table, and L51 is too dense
    to realize this is not a recursive function call, bombarding
    me with a couple dozen warnings and moving all affected
    functions out of the overlayable RAM logic, which eats up so
    much internal RAM I have to write OVERLAY directives, unique
    to each MCU, to get it to fit.

    My work is mostly adding new features, and your average
    feature changes the code in around 2 execution modules.
    Every other change causes a source file or 2 to grow to the
    point where I have to re-factor, so my project file source
    list is NEVER the same between MCUs, and rarely the same
    between revisions of the same MCU.

    So I could possibly create a 'default project file' to copy
    into each directory, for which I would have to delete all
    the file entries, the pre-processor constants, and OVERLAY
    directives, then customize it to the new environment. I had
    heretofore considered this a wash, but with the wish to
    enable lint all the time, it is worth running a check.

    I'll report back when I know.

Reply
  • Let's see if I can apply your advice to my logistics.

    My 'top level BOM' is a system containing 5 MCUs, which
    communicate over several networks. Thus I must maintain 5
    execution modules and around 120 source files to make a
    release.

    The product is offered in 50 different configurations which
    I maintain from a common source deck by changing the values
    of 4 pre-processor constants at build time.

    Four of the 5 applications are based on finite state
    machines, which I implement calling a function pointer
    table, indexed by the state variable. When elements of the
    call tree pass strings as parameters to lower-level
    functions, these strings get stored in the same ?CO? code
    segment as the function pointer table, and L51 is too dense
    to realize this is not a recursive function call, bombarding
    me with a couple dozen warnings and moving all affected
    functions out of the overlayable RAM logic, which eats up so
    much internal RAM I have to write OVERLAY directives, unique
    to each MCU, to get it to fit.

    My work is mostly adding new features, and your average
    feature changes the code in around 2 execution modules.
    Every other change causes a source file or 2 to grow to the
    point where I have to re-factor, so my project file source
    list is NEVER the same between MCUs, and rarely the same
    between revisions of the same MCU.

    So I could possibly create a 'default project file' to copy
    into each directory, for which I would have to delete all
    the file entries, the pre-processor constants, and OVERLAY
    directives, then customize it to the new environment. I had
    heretofore considered this a wash, but with the wish to
    enable lint all the time, it is worth running a check.

    I'll report back when I know.

Children
No data