How to use a const pointer in switch case ?

Q

quakewang

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.
 
R

Richard Heathfield

(e-mail address removed) said:
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)

Why? That's a daft thing to do.
then I use the constan in switch, like:
switch(font) {
case GLUT_BITMAP_8_BY_13: bitmapHeight = 13;

Can't do that. Case values are supposed to be constant integer
expressions.
Then I use gcc to compile them, the gcc always complain:

a8.c:261: error: pointers are not permitted as case values
Right.

a8.c:261: error: case label does not reduce to an integer constant

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

Use integer constants instead of pointers.
 
Q

quakewang

(e-mail address removed) said:



Why? That's a daft thing to do.

I do not want to use like that, but that is the glut's head.
(glut is a mini package for opengl.)
 
I

Ian Collins

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)

And for what reason the header file will define the const to a
(void *)?
The only one I can think of is to antagonise users! What a perverse
thing to do.
 
P

Pierre Asselin

#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;
[ ... ]
}
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

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.
 
G

Guest

Pierre said:
#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;
[ ... ]
}
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

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.

(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.)
 
R

Roberto Waltman

(Pierre Asselin) said:
...
In <GL/glut.h>. Good grief! Why did they have to do that!

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 ]
 
R

Roberto Waltman

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 ----

#include "library.h"
struct hidden
{
...
};

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

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

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 ]
 
K

Keith Thompson

Roberto Waltman said:
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)
[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 "&".)
 
G

Guest

Keith said:
Roberto Waltman said:
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)
[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>

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.
 
K

Keith Thompson

Harald van Dijk said:
Keith Thompson wrote: [...]
<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>

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.

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.
 
C

CBFalconer

Keith said:
Harald van Dijk said:
Keith Thompson wrote: [...]
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.

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.

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.

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.
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top