0

I have an enum which looks like this:

enum class MY_TYPE : int32_t{
    UNKNOWN = 0,
    A = 101,
    B = 102,
    C = 103,
    D = 104,
    E = 105
};

I want to cast given values from and to it.

First of all, is it guaranteed that the following code does not induce undefined behavior?

int32_t library_func(int* tp){ *tp = 275; return 0;}

int main(){
    MY_TYPE d = static_cast<MY_TYPE>(224);
    library_func(reinterpret_cast<int*>(&d));
    std::cout << "d is " << static_cast<int>(d);
}

Is it UB if I cast a value not inside the value range of MY_TYPE? About this, I found the following issue: What happens if you static_cast invalid value to enum class?

This prints 275 as expected. Do I understand the answer correctly that casting any value which fits in the enum's underlying type is fine?

Curunir
  • 1,186
  • 2
  • 13
  • 30
  • 1
    For the most part, `reinterpret_cast` is a clear signal that you have UB. In this case, that signal is correct. A `MY_TYPE` is not an `int`, so you can not treat it as one. – NathanOliver Jul 20 '21 at 19:44
  • 1
    related/dupe: https://stackoverflow.com/questions/33607809/can-an-out-of-range-enum-conversion-produce-a-value-outside-the-underlying-type – NathanOliver Jul 20 '21 at 19:45
  • @NathanOliver if it _was_ an int, it would be fine though? – Curunir Jul 20 '21 at 19:49
  • 1
    Another related Q/A: [Why can't C++11 strongly-typed enum be cast to underlying type via pointer?](https://stackoverflow.com/questions/24566576/why-cant-c11-strongly-typed-enum-be-cast-to-underlying-type-via-pointer) – alter_igel Jul 20 '21 at 19:50
  • @Curunir I believe that is still not allowed, but [this](https://timsong-cpp.github.io/cppwp/basic.lval#11.2) might mean it is okay. I'm having trouble trying to figure out what it means. – NathanOliver Jul 20 '21 at 20:01
  • 1
    @Curunir yes, absolutely. If it **were** an int, you could pass it as a pointer to int, and you'd not have to do any cast. – SergeyA Jul 20 '21 at 20:03
  • @NathanOliver that means that following code is legal: `double* d= reinterpret_cast(new int); *reintepret_cast(d) = 12`. Dynamic type of `*d` is `int`, so you can legally reinterpret_cast it to int* and dereference. – SergeyA Jul 20 '21 at 21:03

1 Answers1

6

Interestingly enough, UB in the example provided is strictly related to the aliasing by pointer, and not assigning enum to value which is not named. If it would not be aliasing by pointer, there would be no UB with using value outside of the enum, i.e. following is A-OK:

int32_t library_func(int32_t tp){ return tp * 10;}

int main(){
    MY_TYPE d = static_cast<MY_TYPE>(224);
    MY_TYPE v {library_func(static_cast<int32_t>(d))};

    std::cout << "v is " << static_cast<int32_t>(v);

}
SergeyA
  • 61,605
  • 5
  • 78
  • 137