How to use a const pointer in switch case ?

Discussion in 'C Programming' started by quakewang, Mar 27, 2007.

  1. quakewang

    quakewang Guest

    hi,

    I have define in a head file like this:
    #define GLUT_BITMAP_9_BY_15 ((void*)2)
    #define GLUT_BITMAP_8_BY_13 ((void*)3)
    #define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4)
    #define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5)

    then I use the constan in switch, like:
    switch(font) {
    case GLUT_BITMAP_8_BY_13: bitmapHeight = 13;
    break;
    case GLUT_BITMAP_9_BY_15: bitmapHeight = 15;
    break;
    case GLUT_BITMAP_TIMES_ROMAN_10: bitmapHeight
    = 10; break;
    case GLUT_BITMAP_TIMES_ROMAN_24: bitmapHeight
    = 24; break;
    case GLUT_BITMAP_HELVETICA_10: bitmapHeight =
    10; break;
    case GLUT_BITMAP_HELVETICA_12: bitmapHeight =
    12; break;
    case GLUT_BITMAP_HELVETICA_18: bitmapHeight =
    18; break;
    }
    Then I use gcc to compile them, the gcc always complain:

    a8.c:261: error: pointers are not permitted as case values
    a8.c:261: error: case label does not reduce to an integer constant
    a8.c:262: error: pointers are not permitted as case values
    a8.c:262: error: case label does not reduce to an integer constant

    And I can not convert the GLUT_BITMAP_9_BY_15 to a integer
    constant, and can not complain pass, how to solve it?

    I know I can use if ... elseif ... statement, really I can not use
    switch in this case? switch can just only use a integer constant? I
    read the "the C programming language", it said so.

    And for what reason the header file will define the const to a
    (void *)?

    any one can give me a answer?

    thanks.
     
    quakewang, Mar 27, 2007
    #1
    1. Advertisements

  2. said:
    Why? That's a daft thing to do.
    Can't do that. Case values are supposed to be constant integer
    expressions.
    Right again.
    Use integer constants instead of pointers.
     
    Richard Heathfield, Mar 27, 2007
    #2
    1. Advertisements

  3. quakewang

    quakewang Guest

    I do not want to use like that, but that is the glut's head.
    (glut is a mini package for opengl.)
     
    quakewang, Mar 27, 2007
    #3
  4. quakewang

    Ian Collins Guest

    The only one I can think of is to antagonise users! What a perverse
    thing to do.
     
    Ian Collins, Mar 27, 2007
    #4
  5. And rightly it should. Try casting them to int,

    /* Editorial comment about braindamaged interface goes here.
    * You should avoid editorial comments in your code, but
    * this one is hard to resist.
    */
    switch((int)font) {
    case (int) GLUT_BITMAP_8_BY_13: bitmapHeight= 13;
    /* ... */
    }

    because I think (int)((void *)3) is an integer constant. You
    may need to cast the "font" variable as well, depending on its
    declared type.
     
    Pierre Asselin, Mar 27, 2007
    #5
  6. quakewang

    Guest Guest

    (int)((void *)3) is not an integer constant expression and cannot be
    portably used in a case label. (However, multiple compilers behave as
    if it is an integer constant expression and accept such constructs
    without any diagnostic.)
     
    Guest, Mar 27, 2007
    #6
  7. I saw similar things many times.
    It's a side effect of creating opaque data structures, (accessed
    trough a void pointer,) and matching a function signature when
    providing literal values as parameters to functions expecting those
    opaque structures.
    (Of course this relies on the assumption that small integers would not
    have the same representation as the address of a "real" structure)
    For example,


    ---- in library.h ----

    extern void *h1;
    extern void *h2;

    extern void func1(void *v,...);
    extern void func2(void *v,...);

    /* valid arguments for func1, func2 ... */

    #define H1 (&h1)
    #define H2 (&h2)

    #define P1 ((void*)1)
    #define P2 ((void*)2)



    ---- In library.c ----

    struct hidden
    {
    ...
    };

    struct hidden h1 = { ... };
    struct hidden h2 = { ... };

    void func1(void *v, ...)
    {
    struct hidden *h = (struct hidden*) v;
    v-> ...
    ...
    }

    void func2(void *v, ...)
    {
    struct hidden *h = (struct hidden*) v;
    v-> ...
    ...
    }




    Roberto Waltman

    [ Please reply to the group,
    return address is invalid ]
     
    Roberto Waltman, Mar 27, 2007
    #7
  8. #include "library.h"
    That should have been h-> ...

    A more useful example:

    void func2(void *v, ...)
    {
    struct hidden *h;
    if ((v == P1) || (v == P2))
    {
    /* do something not using v as */
    /* a struct pointer */
    ...
    }
    else
    {
    /* do something using v as */
    /* a struct pointer */

    h = (struct hidden*) v;
    h-> ...
    ...
    }

    Roberto Waltman

    [ Please reply to the group,
    return address is invalid ]
     
    Roberto Waltman, Mar 27, 2007
    #8
  9. [snip]

    In fact, the C standard does something similar. The second argument
    to the signal() function, and its return value, is of a function
    pointer type. The standard defines three macros, SIG_DFL, SIG_ERR,
    and SIG_IGN, which are constant expressions of this type. They must
    have distinct values unequal to the address of any declarable
    function.

    <OT>
    In the implementations I've checked, they have the values 0, -1, and
    1, respectively, converted to the appropriate type (These
    implementations allow conversions between integer types and
    pointer-to-function types.) Of course, these specific values are not
    required.
    </OT>

    As you say, in both cases this depends on the assumption that small
    integers converted to pointers don't match the address of any actual
    structure or function. In the case of <signal.h>, the declarations
    are part of the implementation, which is free to make whatever
    system-specific assumptions it can get away with. The authors of GLUT
    apparently chose to make the same kind of assumption, which is not
    unreasonable; GLUT probably won't even compile on a DS9K.

    If you *don't* want to make that kind of assumption, you could make
    the macros expand to the addresses of static structures or functions
    that are otherwise unused. For example:

    static struct whatever Dummy_GLUT_BITMAP_9_BY_15;
    #define GLUT_BITMAP_9_BY_15 ((void*)&Dummy_GLUT_BITMAP_9_BY_15)

    ...

    static void __Dummy_SIG_DFL(int) { abort(); }
    /* don't call this function */
    #define SIG_DFL (&__Dummy_Sig_DFL)

    (The "& is usually unnecessary for a function designator, but in this
    case it allows SIG_DFL to be used as the operand of sizeof, and
    disallows its use as the operand of another "&".)
     
    Keith Thompson, Mar 27, 2007
    #9
  10. quakewang

    Guest Guest

    Are you saying implementations are not required to allow conversions
    between integer types and pointer-to-function types? I'm aware that
    it's allowed that no integer type is large enough to store a function
    pointer, but I was under the impression that the conversion itself was
    required to be supported -- that is,

    int main(void) { return 0 && (int) &main; }

    is strictly conforming as far as I know.
     
    Guest, Mar 28, 2007
    #10
  11. Yes, that was what I was saying. Alas, I was wrong, wrong, wrong.

    C99 6.3.2.3:

    An integer may be converted to any pointer type.
    [...]
    Any pointer type may be converted to an integer type.

    What I was thinking of was the fact that function pointers can't be
    directly converted to object pointers or vice versa.
     
    Keith Thompson, Mar 28, 2007
    #11
  12. quakewang

    CBFalconer Guest

    That emasculated quotation is very dangerous. It might persuade
    someone that they can actually do it. The full quote follows.

    [#5] An integer may be converted to any pointer type.
    Except as previously specified, the result is
    implementation-defined, might not be properly aligned, and
    might not point to an entity of the referenced type.49)

    [#6] Any pointer type may be converted to an integer type.
    Except as previously specified, the result is
    implementation-defined. If the result cannot be represented
    in the integer type, the behavior is undefined. The result
    need not be in the range of values of any integer type.
     
    CBFalconer, Mar 28, 2007
    #12
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.