Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guard code after switch on enum is never reached

Tags:

c++

I have just hit a confusing problem when trying to compile some code using g++ 4.4.3.

The code below compiles fine, but instead of hitting the expected assert when I pass an 'invalid' enum value, the function just returns 1. What I find even stranger is that when I uncomment the lines pertaining to the E3 enum value, things start working as expected.

The fact that there is no default entry in the switch block is by design. We compile with the -Wall option to get warnings of unhandled enum values.

enum MyEnum
{
    E1,
    E2, 
    //E3
};

int doSomethingWithEnum(MyEnum myEnum)
{
    switch (myEnum)
    {
        case E1: return 1;
        case E2: return 2;
        //case E3: return 3;
    }

    assert(!"Should never get here");
    return -1;
}

int main(int argc, char **argv)
{
    // Should trigger assert, but actually returns 1
    int retVal =  doSomethingWithEnum(static_cast<MyEnum>(4));
    std::cout << "RetVal=" << retVal << std::endl;

    return 0;
}
like image 655
hysj Avatar asked Dec 30 '11 12:12

hysj


Video Answer


1 Answers

Your switch statement will be compiled into this (g++ 4.4.5):

    cmpl    $1, %eax
    je      .L3
    movl    $1, %eax
    jmp     .L4
.L3:
    movl    $2, %eax
.L4:
    leave
    ret

As can be seen, the assert is optimized away completely, and the compiler elects to compare against E2 and return 1 in all other cases. With three enum values it can't do that.

Section 5.2.9 of the C++98 standard (static cast) gives the reason for allowing this:

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting enumeration value is unspecified.

In other words, the compiler is free to use whatever enum value it wants, (in this case E1) if you try to use an illegal value. This includes doing the intuitive thing and using the supplied illegal value or using different values depending on the circumstances, which is why the behavior changes depending on the number of enum values.

like image 88
Emil Styrke Avatar answered Sep 19 '22 05:09

Emil Styrke