constants in switch case constructs

I

InuY4sha

Hi list,
I've got the following stuff

struct mystruct {
const char *first;
const char *second;
const int val;
};
static const struct mystruct data[] = {
{ "hello", "world", 4 },
{ "hello", "friend", 5 }
};

void myfunc(int myvar){
switch(myvar)
{
case(data[0].val): ///ERROR!
{
printf("%s",data[0].first);
break;
}
default:
{
break;
}
}
}
and it gives me this error: "case label does not reduce to an integer
constant" with reference to the line marked with the "ERROR!" comment.
I was wondering why it complained considering that, according to the
definition, that IS a constant..
I can use an if statement I know .. but I seek knowledge not
workarounds ;)
 
E

Eric Sosman

InuY4sha said:
Hi list,
I've got the following stuff

struct mystruct {
const char *first;
const char *second;
const int val;
};
static const struct mystruct data[] = {
{ "hello", "world", 4 },
{ "hello", "friend", 5 }
};

void myfunc(int myvar){
switch(myvar)
{
case(data[0].val): ///ERROR!
{
printf("%s",data[0].first);
break;
}
default:
{
break;
}
}
}
and it gives me this error: "case label does not reduce to an integer
constant" with reference to the line marked with the "ERROR!" comment.
I was wondering why it complained considering that, according to the
definition, that IS a constant..
I can use an if statement I know .. but I seek knowledge not
workarounds ;)

In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

This confusion crops up fairly often, in various guises. See
Question 11.8 in the comp.lang.c Frequently Asked Questions (FAQ)
list at <http://www.c-faq.com/>.
 
I

InuY4sha

In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

This confusion crops up fairly often, in various guises. See
Question 11.8 in the comp.lang.c Frequently Asked Questions (FAQ)
list at <http://www.c-faq.com/>.

Thanks for having clarified the concept. I'll use some defines then.
Regards
 
J

James Kuyper

InuY4sha said:
Hi list,
I've got the following stuff

struct mystruct {
const char *first;
const char *second;
const int val;
};
static const struct mystruct data[] = {
{ "hello", "world", 4 },
{ "hello", "friend", 5 }
};

void myfunc(int myvar){
switch(myvar)
{
case(data[0].val): ///ERROR!
{
printf("%s",data[0].first);
break;
}
default:
{
break;
}
}
}
and it gives me this error: "case label does not reduce to an integer
constant" with reference to the line marked with the "ERROR!" comment.
I was wondering why it complained considering that, according to the
definition, that IS a constant..

What is required in this contest is what the standard calls an "integer
constant expression" (ICE). This is a special phrase whose meaning
cannot be determined simply by examining the words that make it up,
which might mislead you into expecting that an ICE is an expression with
integer type and a value that is constant. In order to understand what
an ICE is, you have to read the Standard's definition of that term:

"An integer constant expression shall have integer type and shall only
have operands that are integer constants, enumeration constants,
character constants, sizeof expressions whose results are integer
constants, and floating constants that are the immediate operands of
casts. Cast operators in an integer constant expression shall only
convert arithmetic types to integer types, except as part of an operand
to the sizeof operator." (6.6p6)

In the case of data[0].val, note that the left operand of the subscript
operator is an array, which is something not permitted in an ICE.
Furthermore, the left operand of your member selection operator is a
struct, and the right operand is the name of a struct member; neither of
those are allowed in an ICE, either.

If you're used to C++, the rules are different in that language. A
static const object initialized with an integer constant expression is
itself an integer constant expression. However, you compiled it as C
code, and the rules are a bit stricter in that language.
 
B

Bart

struct mystruct {
        const char      *first;
        const char      *second;
        const int         val;};

static const struct mystruct data[] = {
        { "hello", "world", 4 },
        { "hello", "friend", 5 }
     switch(myvar)
     {
         case(data[0].val):        ///ERROR!
and it gives me this error: "case label does not reduce to an integer
constant" with reference to the line marked with the "ERROR!" comment.
I was wondering why it complained considering that, according to the
definition, that IS a constant..
I can use an if statement I know .. but I seek knowledge not
workarounds  ;)

The compiler's idea of an integer constant is a value that is *not*
stored in the program's memory.

In other words, it should be something created using #define or enum{}
or sizeof, or an expression using such constants if it can evaluate it
at compile-time.
 
J

James Kuyper

Eric said:
InuY4sha said:
Hi list,
I've got the following stuff

struct mystruct {
const char *first;
const char *second;
const int val;
};
static const struct mystruct data[] = {
{ "hello", "world", 4 },
{ "hello", "friend", 5 }
};

void myfunc(int myvar){
switch(myvar)
{
case(data[0].val): ///ERROR!
{
printf("%s",data[0].first);
break;
}
default:
{
break;
}
}
}
and it gives me this error: "case label does not reduce to an integer
constant" with reference to the line marked with the "ERROR!" comment.
I was wondering why it complained considering that, according to the
definition, that IS a constant..
I can use an if statement I know .. but I seek knowledge not
workarounds ;)

In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

It is computable at compile time: it's 4. That's what makes it feasible
for it to qualify as a C++ "integral constant expression", even though
it does not qualify as a C "integer constant expression". It's not about
what is computable, but about what C requires the implementation to accept.
 
S

Stephen Sprunk

James said:
Eric said:
In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

It is computable at compile time: it's 4. That's what makes it feasible
for it to qualify as a C++ "integral constant expression", even though
it does not qualify as a C "integer constant expression". It's not about
what is computable, but about what C requires the implementation to accept.

So you would think. However, since (in C) "const" means "read-only" and
not "constant", as one would expect, the compiler cannot assume that a
"const" object is a constant and therefore is not allowed to compute it
at compile time. The code could theoretically modify that "const"
object via a cast or some other means, changing its "constant" value.

This is one of the areas of C that I absolutely hate; is there even a
remote chance that ISO will "fix" this in a future version to be more
like C++, which actually believes that "const" objects are constants?

S
 
E

Eric Sosman

Stephen said:
James said:
Eric said:
In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."
It is computable at compile time: it's 4. That's what makes it feasible
for it to qualify as a C++ "integral constant expression", even though
it does not qualify as a C "integer constant expression". It's not about
what is computable, but about what C requires the implementation to accept.

So you would think. However, since (in C) "const" means "read-only" and
not "constant", as one would expect, the compiler cannot assume that a
"const" object is a constant and therefore is not allowed to compute it
at compile time. The code could theoretically modify that "const"
object via a cast or some other means, changing its "constant" value.

Doing so would invoke undefined behavior anyhow. After
the change a `switch' would be within its rights to misbehave;
the compiler is under no obligation to make the program act
sensibly once U.B. occurs.
This is one of the areas of C that I absolutely hate; is there even a
remote chance that ISO will "fix" this in a future version to be more
like C++, which actually believes that "const" objects are constants?

comp.std.c might be a better place to ask about possible
changes in future versions of the Standard. Meanwhile, it's
quite clear that some `const' values cannot possibly be
computed at compile time:

extern const int foo, bar;

switch (rand()) {
case foo: ...; break;
case bar: ...; break;
}
 
K

Keith Thompson

Eric Sosman said:
Stephen said:
James said:
Eric Sosman wrote:
In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."
It is computable at compile time: it's 4. That's what makes it feasible
for it to qualify as a C++ "integral constant expression", even though
it does not qualify as a C "integer constant expression". It's not about
what is computable, but about what C requires the implementation to accept.

So you would think. However, since (in C) "const" means "read-only" and
not "constant", as one would expect, the compiler cannot assume that a
"const" object is a constant and therefore is not allowed to compute it
at compile time. The code could theoretically modify that "const"
object via a cast or some other means, changing its "constant" value.

Doing so would invoke undefined behavior anyhow. After
the change a `switch' would be within its rights to misbehave;
the compiler is under no obligation to make the program act
sensibly once U.B. occurs.
This is one of the areas of C that I absolutely hate; is there even a
remote chance that ISO will "fix" this in a future version to be more
like C++, which actually believes that "const" objects are constants?

comp.std.c might be a better place to ask about possible
changes in future versions of the Standard. Meanwhile, it's
quite clear that some `const' values cannot possibly be
computed at compile time:

extern const int foo, bar;

switch (rand()) {
case foo: ...; break;
case bar: ...; break;
}

Or, for that matter:

const int foo = rand();
switch (42) {
case foo: ...; break;
}

C++ has rules that define which const expressions are treated
as compile-time constants; probably importing those rules into C
wouldn't be horribly difficult, and I would support doing so.
 
J

jameskuyper

Stephen said:
James said:
Eric said:
In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

It is computable at compile time: it's 4. That's what makes it feasible
for it to qualify as a C++ "integral constant expression", even though
it does not qualify as a C "integer constant expression". It's not about
what is computable, but about what C requires the implementation to accept.

So you would think. However, since (in C) "const" means "read-only" and
not "constant", as one would expect, the compiler cannot assume that a
"const" object is a constant

Any code that you might otherwise expect to result in modification of
the value of an object defined as 'const' has undefined behavior.
Whether or not such code will actually modify the object is one of the
many things that are not defined when that happens. This is why they
are permitted to store such objects in memory that is read-only during
the lifetime of those objects. Note that this only applies to a
'const' keyword in the definition of the object itself, and only if
that keyword applies to the object being defined.

An implementation is permitted to assume that the program it is
compiling does not have undefined behavior (the consequences of such
assumptions being wrong are one of the many forms that undefined
behavior can take). As a result, the compiler CAN assume that an
object defined as const, like this one, is indeed constant, even if
such code would in fact modify such an object.

The issue is not whether the compiler could make that assumption, nor
even whether the assumption is valid; it's whether the C standard
permits the value of such objects to be used where an ICE is required.
It doesn't, but there's no inherent reason why it couldn't.
... and therefore is not allowed to compute it
at compile time. The code could theoretically modify that "const"
object via a cast or some other means, changing its "constant" value.

That cannot be done with defined behavior.

int a = 3;
const int b = 5;

const int *p = &a;
int *q = (int *)p;

*q = 4; // This has defined behavior
p = &b;
q = (int*)p;

*q = 6; // This has undefined behavior (6.7.3p5)
 
R

REH

If you're used to C++, the rules are different in that language. A
static const object initialized with an integer constant expression is
itself an integer constant expression. However, you compiled it as C
code, and the rules are a bit stricter in that language.

The object doesn't even have to be static. A const int local to a
function that is initialized with an ICE is still an ICE.

REH
 
N

Nobody

In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

It is computable at compile time: it's 4.

It's initial value is 4; it isn't guaranteed to still have that value at
the point that myfunc() is called.
 
J

jameskuyper

Nobody said:
In C, `const' does not mean "constant," but something closer
to "read-only." The expression `data[0].val' is not a constant
computable at compile time, not under C's definition of "integer
constant expression."

It is computable at compile time: it's 4.

It's initial value is 4; it isn't guaranteed to still have that value at
the point that myfunc() is called.

Any operation that would modify it has undefined behavior. If the
program has defined behavior, it (and the compiler) can count of that
value being unmodified.

If the program has undefined behavior, the compiler can do whatever it
wants, including (as one possibility) ignoring the modification, and
using a constant value of 4 in every location where there is an
expression like data[0].val.

Either way, compile-time evaluation of all such expressions is
permitted; and could have been made mandatory, had the C committee
chosen to make it so.
 
J

James Kuyper

pete said:
No, it isn't.

This won't compile in C90:

He was responding to my comments comparing the rules in C++ with the
rules in C. What he wrote was about the C++ rules, and AFAIK, was quite
correct.
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top