il_mix
il_mix

Reputation: 591

Use const struct member in switch/case statement

I would like to use a (const) struct member as a selector in switch/case statement. The problem is that I get a "case expression not constant" or "illegal constant expression". Here is a brief example

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct _myStruct
{
    unsigned int value_;
    unsigned int index_;
} myStruct;

#define VALUE_0 0
const unsigned int VALUE_1 = 1;
const myStruct VALUE_2 = {2, 0};

int main()
{
  srand((unsigned int)time(0));

  switch(rand()%4)
  {
    case VALUE_0:
      printf("Value is 0\n");
      break;
    case VALUE_1:
      printf("Value is 1\n");
      break;
    case VALUE_2.value_:
      printf("Value is 2\n");
      break;
    case 3:
      printf("Value is 3\n");
      break;
  }

  return 0;
}

The case VALUE_2.value_ option generates the compiler error. BTW, VALUE_2 is indeed a constant.

I'm working with ANSI C. C++ gives the same error, anyway.

Any hints?

Upvotes: 1

Views: 4932

Answers (3)

pcdangio
pcdangio

Reputation: 332

If you make the const member static, it will satisfy the requirements for switch.

struct my_struct
{
    static const int value_a = 1;
    static const int value_b = 2;

    void handle_value(int value)
    {
        switch(value)
        {
            case my_struct::value_a:
            {
                // Do something fancy
                break;
            }
            case my_struct::value_b:
            {
                // Do something fancy
                break;
            }
            default:
            {
                // Do something fancy
                break;
            }
        }
    }
};

Upvotes: 0

mafso
mafso

Reputation: 5543

In short, const doesn't mean “constant expression” (the const keyword is a little confusing IMO). Precisely,

C11 6.8.4.2 p.2 (emph. mine)

The expression of each case label shall be an integer constant expression […]

So, the question is, what an integer constant expression is; C11 addresses this in 6.6:

Description (p. 2)

A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be.

The Constraints section (p. 3/4) goes on:

Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.115)

Each constant expression shall evaluate to a constant that is in the range of representable values for its type.

And the footnote:

115) The operand of a sizeof or _Alignof operator is usually not evaluated (6.5.3.4).

Semantics (p. 5/6)

An expression that evaluates to a constant is required in several contexts. […] 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, _Alignof expressions, 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 or _Alignof operator. [emph. mine, omitted footnotes 116 and 117]

The emphasized list of allowed operands doesn't contain variables (at least not in general, sizeof VALUE_2 would be OK), no matter if they are const-qualified or not (you mentioned C++ in your question; if you're interested, have a look at C++11's constexpr).

And (ibid. p. 10)

An implementation may accept other forms of constant expressions.

I quoted C11; C99 is basically the same (but doesn't have the _Alignof operator), with the same sections.

HTH

Upvotes: 1

pablo1977
pablo1977

Reputation: 4433

In C, a const-qualified variable means "read only object in memory", but it's not considered an integer constant expression.

An integer constant expression is, roughly speaking, an expression involving only literal integer constants as operands.

In particular, a #define-d constant which expand to an integer literal is a valid constant here.

The case labels require integer constant expressions, and not variables. The const qualifier is not making any difference, and this kind of objects are not allowed.

Upvotes: 2

Related Questions