Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switch error:: cannot appear in a constant-expression

this is a strange one...

I am playing with some decompression algo. Instead of going through the char buffer[] and looping until a stop-bit in buffer[i] is found, I am trying use some bit-mask techniques but with chars.

I have the following example:

// In a *.h file  
const char ch = '\x81';  
// To avoid Endianess  
union CharUInt  
{  
    char sz[4];  
    unsigned int u;  
};  
// Legal because char[] is declared before uint32 in the union  
const CharUInt Mask1 = {'\x81', '\x0', '\x0', '\x81'};  
const CharUInt Mask2 = {'\x0', '\x81', '\x81', '\x0'};  
// Proxy / Auxillary uint32 as usimg Mask2.u in the switch blocked produced the same errors  
const unsigned int uMask1 = Mask1.u;  
const unsigned int uMask2 = Mask2.u;  
const unsigned int uMask_ = (uMask1 & uMask2);  
// buf is always long enough  
bool Foo(char buf[])  
{  
    const CharUInt Type = {buf[0], buf[1], buf[2], buf[3]};  
    unsigned int uType = (Type.u & uMask_);  
    switch(uType)  
    {  
    case uMask1:  
        // do stuff  
    case uMask2:    
        // do more stuff  
        return true;  
        break;  
    default:  
        // do different stuff  
        return false;  
        break;  
    }  
};  

Without considering the syntax of the union stuff (the actual code compiles run fine for that) and without considering whether the function-return for Foo is pretty, I get
'uMask1' cannot appear in a constant-expression
and if the unions themselves are used, I get
'Mask1' cannot appear in a constant-expression
'.' cannot appear in a constant-expression
and of course the errors also apply for uMask2 and Mask2.u

What am I missing?

Thanks in advance

like image 400
globalcouchsurfer Avatar asked Sep 29 '10 15:09

globalcouchsurfer


2 Answers

The confusion comes from the fact that const and const are two.

The case's in the switch statement need 'constant expressions'. Or in other words: expressions that can be 'calculated' by the compiler, at compile-time. This could be a hard-coded number (like 42), or something that has been defined before as a number (using #define).

Const is also used by the compiler with the meaning "once this variable has a value, it won't change anymore". E.g. in the following code:

void myFunction (const int value)
{
...
}

value will be const. I will not be able to change the value of const, but this does not make it a 'constant expression' for the compiler.

In your case, uMask1 is const (can't change it anymore) but not a constant expression.

like image 140
Patrick Avatar answered Oct 20 '22 18:10

Patrick


case condition expression must be of integral type, or convertible to integral type, and must be const.

6.4.2 [stmt.switch]

The condition shall be of integral type, enumeration type, or of a class type for which a single conversion function to integral or enumeration type exists (12.3). If the condition is of class type, the condition is converted by calling that conversion function, and the result of the conversion is used in place of the original condition for the remainder of this section. Integral promotions are performed. Any statement within the switch statement can be labeled with one or more case labels as follows:

case constant-expression :

where the constant-expression shall be an integral constant-expression. The integral constant-expression (5.19) is implicitly converted to the promoted type of the switch condition. No two of the case constants in the same switch shall have the same value after conversion to the promoted type of the switch condition.

Your expression isn't a constant expression, even though the variable itself is const, so you can't switch on it. You'll need to use an if.

You have another problem though:

You create a union,

union CharUInt  
{  
    char sz[4];  
    unsigned int u;  
};

...then you initialize the sz member of that union,

static const CharUInt Mask1 = {'\x81', '\x0', '\x0', '\x81'};  

...and then you access the u member of that union.

static const unsigned int uMask1 = Mask1.u;  

This evokes undefined behavior according to the standard. In the language of the Standard, 2 members of a union can't be active at one time. Meaning you can't treat a union like a caster.

like image 26
John Dibling Avatar answered Oct 20 '22 17:10

John Dibling