-3

NOTE1: I have figured the problem before asking it here but I just want a discussion about this non-intuitive behavior in my opinion

NOTE2: This happens on gcc 7.5

#include <stdio.h>

enum lulu
{
        XXX=-2,//if I comment this it considers the enum as unsigned
               //and the cast to long is telling a totally different story
        AAA=10,
        BBB,
        CCC
};

int test_long(long param)
{
        printf("param=%ld\n",param);
        return 0;
}

int main(void)
{
        lulu l1 = AAA;
        lulu l2 = lulu(-AAA);
        printf("parameters to be cast to long: <%X> <%X>\n",l1,l2);
        test_long(static_cast<long>(l1));
        test_long(static_cast<long>(l2));
        int val1 = l1;
        int val2 = l2;

        printf("%d %d\n",val1,val2);

        int i = -6;
        test_long(static_cast<long>(i));
        return 0;
}

The problem is this static_cast is extremely non-intuitive.

In the above example if I compile it like described below I get the following:

# g++ -o long_cast -Wall long_cast.cpp
# ./long_cast
parameters to be cast to long: <A> <FFFFFFF6>
param=10
param=-10
10 -10
param=-6
#

but if I comment the XXX definition (a negative enum member) I get a totally different story

# ./long_cast
parameters to be cast to long: <A> <FFFFFFF6>
param=10
param=4294967286
10 -10
param=-6
#

What is the proper way to handle this?

I did an intermediate step in converting the value to int and then did the static cast.

Any other suggestions?

INS
  • 10,594
  • 7
  • 58
  • 89
  • 8
    "*I just want a discussion about this non-intuitive behavior*" - this is a Q&A site, not a discussion forum. "*I have figured the problem before asking it here*" - you are free to share knowledge, but it still [needs to be presented in a Q&A format](https://stackoverflow.com/help/self-answer). – Remy Lebeau Aug 04 '21 at 19:39
  • 1
    you can post an anwer to your own question if you like though – 463035818_is_not_an_ai Aug 04 '21 at 19:40
  • 1
    `lulu l2 = lulu(-AAA);` is undefined behaviour. – 273K Aug 04 '21 at 19:41
  • `-x` when `x` is a small unsigned integral type will be a very large unsigned integral type because unsigned integer arithmetic is modular. As Remy points out, there's not really a question here. – Nathan Pierson Aug 04 '21 at 19:41
  • @S.M. What makes it undefined behavior? – Nathan Pierson Aug 04 '21 at 19:42
  • 2
    Note: In Modern C++ you can [explicitly state the underlying type](https://en.cppreference.com/w/cpp/language/enum) of an `enum`. – user4581301 Aug 04 '21 at 19:43
  • 1
    @S.M. wrong. It is not. – SergeyA Aug 04 '21 at 19:44
  • @NathanPierson nothing does. – SergeyA Aug 04 '21 at 19:44
  • @NathanPierson see [What happens if you static_cast invalid value to enum class?](https://stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class). – 273K Aug 04 '21 at 19:46
  • "The problem is this static_cast is extremely non-intuitive." why did you put the cast in the first place? It is superfluous (if I don't miss something...) – 463035818_is_not_an_ai Aug 04 '21 at 19:46
  • @S.M. I guess that could happen if the underlying type chosen for `lulu` is actually narrower than `int`, in which case `-AAA` could well be outside the representable range of values. On my implementation though `lulu`'s underlying value is `int`, regardless of whether the identifier `XXX = -2` is included or not. – Nathan Pierson Aug 04 '21 at 19:52
  • @NathanPierson it might be a compiler particularity. I'm using g++ 7.5.0 on my dev machine. – INS Aug 04 '21 at 19:53
  • If `XXX` is commented out, then the valid range of `lulu` is 0 .. 15, and outside that range is undefined behavior (which is what I think S.M. is referring to). There are several ways to fix this problem, but since you've already figured out the problem fixing it is probably irrelevant. *The problem is this static_cast is extremely non-intuitive.* I do not concur, I'd say enum underlying type is a bit non-intuitive if you try to do something tricky. – Eljay Aug 04 '21 at 19:56
  • @Eljay That is by no means guaranteed to be the case. Compilers are perfectly free to choose `int` as the underlying type even though you can represent all identifiers with fewer bits, at which point the valid range of `lulu` is `INT_MIN` to `INT_MAX`. – Nathan Pierson Aug 04 '21 at 19:58
  • 1
    @NathanPierson • according to CppReference [enum](https://en.cppreference.com/w/cpp/language/enum), values outside the minimal bit-range of the enumeration values is undefined behavior (as of C++17), or unspecified behavior (pre-C++17). But that's non-canonical, and I don't have the standard's chapter & verse on hand to cite. – Eljay Aug 04 '21 at 20:02
  • Oops, my bad. Thanks for the correction. – Nathan Pierson Aug 04 '21 at 20:03
  • @NathanPierson • no problem. :-) C++ is large and complex, and has a lot of dark corners and sharp edges. – Eljay Aug 04 '21 at 20:04
  • See [this](https://timsong-cpp.github.io/cppwp/enum#dcl.enum-7). The compiler is free to use an type as long as the values fit it. Without `XXX` in the enum, all values can be represented in an unsigned type, with `XXX`, a signed integer has to be used. – NathanOliver Aug 04 '21 at 20:11
  • 1
    @Eljay Found it: § 7.6.1.8.10 . I know this because the whole thing made me nuts for the past 1-2 hours, since all you have to do is to fix the type and its not UB. Because CPP doesn't prevent you from having values with enum type not represented by a enumeration. – Superlokkus Aug 05 '21 at 16:06

1 Answers1

-1

The solution, as stated in the code is to temporary convert to a signed integer variable and then make a static_cast to long.

int val2 = l2;

long lval2 = static_cast<long>(val2);
INS
  • 10,594
  • 7
  • 58
  • 89