CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Unexpected behaviour when casting to enum

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
SamMeredith



Joined: 13 Jul 2018
Posts: 25

View user's profile Send private message

Unexpected behaviour when casting to enum
PostPosted: Thu Feb 06, 2025 12:22 pm     Reply with quote

Compiler verson: 5.118
Device: DSPIC33EP512MC806

Consider the following example code:

Code:

#include <33EP512MC806.h>

// #device CCS2

#case

#use delay( crystal=12Mhz, clock=120Mhz, AUX:clock=48Mhz )

#pin_select U3RX = PIN_F1
#pin_select U3TX = PIN_F2
#use rs232(UART3, baud = 115200, parity = N, bits = 8, errors, TIMEOUT = 1, stream = DEBUGSTREAM)

#word U3STA = getenv("SFR:U3STA")
#bit U3TRMT = U3STA.8

#define DEBUGPRINTF( x, ... ) {  \
    fprintf( DEBUGSTREAM, x, __VA_ARGS__ );  \
    while ( !U3TRMT ) {};   \
}

typedef enum
{
    OFF,
    ON
} STATE;

typedef enum
{
    TRISTATE_OFF,
    TRISTATE_ON,
    UNKNOWN
} TRISTATE;

void main()
{
    delay_ms(100);

    int1 tmp = 1;

    STATE assign_enum = ON;                                 // 01
    STATE assign_literal = 1;                               // 01
    STATE assign_variable = tmp;                            // 01
    STATE cast_enum = (STATE)ON;                            // 00 ??
    STATE cast_literal = (STATE)1;                          // 00 ??
    STATE cast_variable = (STATE)tmp;                       // 01
   
   DEBUGPRINTF(" assign_enum=%02X\r\n assign_literal=%02X\r\n assign_variable=%02X\r\n cast_enum=%02X\r\n cast_literal=%02X\r\n cast_variable=%02X\r\n",
        assign_enum, assign_literal, assign_variable, cast_enum, cast_literal, cast_variable);

    int tmp2 = 2;

    TRISTATE tristate_assign_enum = UNKNOWN;                // 02
    TRISTATE tristate_assign_literal = 2;                   // 02
    TRISTATE tristate_assign_variable = tmp2;               // 02
    TRISTATE tristate_cast_enum = (TRISTATE)UNKNOWN;        // 02
    TRISTATE tristate_cast_literal = (TRISTATE)2;           // 02
    TRISTATE tristate_cast_variable = (TRISTATE)tmp2;       // 02
   
   DEBUGPRINTF(" assign_enum=%02X\r\n assign_literal=%02X\r\n assign_variable=%02X\r\n cast_enum=%02X\r\n cast_literal=%02X\r\n cast_variable=%02X\r\n",
        tristate_assign_enum, tristate_assign_literal, tristate_assign_variable, tristate_cast_enum, tristate_cast_literal, tristate_cast_variable);

    tmp2 = 259;

    tristate_assign_literal = 259;                          // 03
    tristate_assign_variable = tmp2;                        // 03
    tristate_cast_literal = (TRISTATE)259;                  // 03
    tristate_cast_variable = (TRISTATE)tmp2;                // 03
   
   DEBUGPRINTF(" assign_literal=%02X\r\n assign_variable=%02X\r\n cast_literal=%02X\r\n cast_variable=%02X\r\n",
        tristate_assign_literal, tristate_assign_variable, tristate_cast_literal, tristate_cast_variable);

    while(TRUE) {}
}


The TRISTATE enum with 3 states behaves as I would expect. TRISTATE variables are represented as a single byte and casting behaves normally. I believe overflowing an enum is undefined behaviour in ANSII C but the CCS behaviour of simply wrapping makes sense.

The STATE enum however does something strange when explicitly casting. I would expect both cast_enum and cast_literal to be 1, but they are not.

Taking a look at the .LST file we can see what happens

Quote:

.................... int1 tmp = 1;
....................
.................... STATE assign_enum = ON; // 01
.................... STATE assign_literal = 1; // 01
.................... STATE assign_variable = tmp; // 01
.................... STATE cast_enum = (STATE)ON; // 00 ??
.................... STATE cast_literal = (STATE)1; // 00 ??
.................... STATE cast_variable = (STATE)tmp; // 01
0038E: BSET.B 1002.0
00390: BSET.B 1002.1
00392: BSET.B 1002.2
00394: BCLR.B 1002.3
00396: BTSS.B 1002.0
00398: BRA 39C
0039A: BSET.B 1002.3
0039C: BCLR.B 1002.4
0039E: BCLR.B 1002.5
003A0: BCLR.B 1002.6
003A2: BTSS.B 1002.0
003A4: BRA 3A8
003A6: BSET.B 1002.6


The assignments make sense but the casts seem strange to me. The compiler just does a direct BCLR.B

I can't come up with an explanation for cast_enum and cast_literal evaluating to 0.
I found a reference to CCS compilation modes, and indeed #DEVICE=CCS2 behaves as I would expect (they evaluate to 1), but even with that knowledge the behaviour in the default mode doesn't make sense to me.

Does this seem like a bug, or is there a logical explanation for the behaviour?

EDIT: Swapped the order of enums to make more sense
Ttelmah



Joined: 11 Mar 2010
Posts: 19730

View user's profile Send private message

PostPosted: Sat Feb 08, 2025 2:57 am     Reply with quote

Not really. Very Happy

Most C's, will actually give a warning if you cast like this, that you are
'mixing enum types'.
Your STATE type is being optimised to an int1, which sometimes has slightly
'odd' rules about what can and cannot be done, and since it is not actually
an int, the C appears to be making an error on the explicit cast. It gets
it right if you use the implicit cast though.
Normally all enum's are ints, this is an oddity because this one is not.

I have to say I dislike your use of capitals here. In C is it a 'semi standard' to
reserve ALL CAPITALS for macro defines, so these are easy to see. The norm
is also to use _t for declared types, so:

Code:

typedef enum
{
    TRISTATE_OFF,
    TRISTATE_ON,
    UNKNOWN
} tristate_t;


Is the standard way to do a declaration like this, which makes it much
less likely to make mistakes in the future or if the code is being passed
to another person.

Suggest you just use the implicit cast to do this, but report it to CCS
as a 'noted oddity', so they can fix it in the future.
SamMeredith



Joined: 13 Jul 2018
Posts: 25

View user's profile Send private message

PostPosted: Fri Feb 14, 2025 6:38 am     Reply with quote

Thanks Ttelmah, I'll report it to CCS.

I was trying to find a proper reference in the C spec but couldn't find one. As far as I could see enums in standard C will never be smaller than a char anyway.

I completely agree with you on capitalisation and _t for declared types.
I do exactly that on all my real code (VSCode highlights _t nicely).
Not sure why I didn't on the example. I'll blame it on being late one evening.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group