• AVR Freaks

Hot!Enum with negative member fail

Page: 12 > Showing page 1 of 2
Author
jtnum
Starting Member
  • Total Posts : 44
  • Reward points : 0
  • Joined: 2003/11/07 12:37:02
  • Status: offline
2019/10/16 09:37:29 (permalink)
0

Enum with negative member fail

I have a strange error with code that has worked with previous C18 and XC8.  This could be pilot error, but when other simple code is substituted, it takes the desired route.
The enum has a negative member and when used in an if statement, my last build fails to run the desired code.  See the alternative code that works.
I believe an enum is an integer, so that is why 1 example were cast to (INT). in the if statement.
 
Resources
  1. Windows 10 64-bit Pro
  2. MPLAB XIDE V5.20
  3. XC8 V2.00
 
typedef char CHAR;
typedef int INT;
CHAR  g_cFaultCode=0;                               // Process GatewayFault Code
INT iTemp;
 
// Lowest number are the highest priority fault
//  1-10 are fatal errors
typedef enum
{
    PGWFLT_FATAL_NON_SPEC       = -8, 
    PGWFLT_EXT_CLK              = -7,
    PGWFLT_BROWNOUT             = -6,
    PGWFLT_XDI_SHUTDN_ALARM     = -5,            
    PGWFLT_GPDI_SHUTDN_ALARM    = -4,
    PGWFLT_INPUT_RANGE          = -3,
    PGWFLT_NO_SLCNET_COMM       = -2, 
    PGWFLT_CRITICAL_LE          = -2,   // Faults <= are Shutdonw Alms        
    PGWFLT_NONE                 =  0,
 
    // Warning faults - auto resettable
    PGWFLT_RTD1                 = 20, // 0x14
    PGWFLT_RTD2                 = 21, // 0x15
    PGWFLT_GPA1                 = 22, // 0x16
    PGWFLT_GPA2                 = 23, // 0x17
    PGWFLT_PID1                 = 24, // 0x18
    PGWFLT_PID2                 = 25, // 0x19
    PGWFLT_SPM1                 = 26, // 0x1A
    PGWFLT_SPM2                 = 27, // 0x1B
 
 
    PGWFLT_PARM                 = 30,  // 0x1E      Parameter Err
    PGWFLT_MAX                  = 30
}PGWFLTCODE;
 
 
Example 1
                if ((INT)(g_cFaultCode > PGWFLT_NO_SLCNET_COMM) )
                {
                               Desired code Does NOT run
}
               
Example 2
if ((INT)g_cFaultCode > (INT)PGWFLT_NO_SLCNET_COMM ) // Does NOT work 
                {
                               Desired code Does NOT run
}
 
Example 3
if ((INT)g_cFaultCode > (INT)-2 ) // works              
                {
                                Desired code Runs
}
               
Example 4
                iTemp = PGWFLT_NO_SLCNET_COMM;
               if ((INT)g_cFaultCode > iTemp)  //This statement works
                {
                                Desired code Runs
}             
#1

20 Replies Related Threads

    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11406
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:05:34 (permalink)
    +2 (2)
    Never use plain char as an integer, because its signedness is implementation defined.  You should be using "signed char" in this code.
    #2
    jtnum
    Starting Member
    • Total Posts : 44
    • Reward points : 0
    • Joined: 2003/11/07 12:37:02
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:17:38 (permalink)
    0
    ok, thanks.  I would have thought the cast to an int would do the trick, but I guess not.
    #3
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11406
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:24:03 (permalink)
    +1 (1)
    If you put -1 in an unsigned char, it will have the the value 255.  Casting 255 to int will not turn it back into -1.
    #4
    du00000001
    Just Some Member
    • Total Posts : 3173
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:25:52 (permalink)
    0
    An enum is an enum is an enum ...
     
    Enums are different: depending on the max. value assigned to one of the elements, an enum usually will occupy a byte (if all values fit 8 Bits) or a word - on the compiler's decision. (Not sure about larger sizes. And n.b. that I'm avoiding the mention of char/int - whether signed or unsigned!)
     
    As the enum type is a quite special type, type casting may or may not result in "correct" sign promotion. Again: an enum is not compatible with s/uint8_t resp. s/uint16_t. It is - intentionally - "from an-oth-er world".
     
    Your issues could be explained considering that your enum might just occupy an unsigned byte and sign promotion doesn't take place...

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #5
    1and0
    Access is Denied
    • Total Posts : 9882
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:34:36 (permalink)
    0
    As I understand it, the type of that enum() is an "int". So shouldn't the comparison promote "g_cFaultCode" to an "int"?
     
    #6
    du00000001
    Just Some Member
    • Total Posts : 3173
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:53:55 (permalink)
    0
    @1and0
    According to my experience (not limited to just gcc), an enum doesn't use more space than necessary. But this may vary between compiler implementations.
     
    The other thing: when promoting an unsigned char to signed int, there might be no sign promotion. (See jtemple's post.)

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #7
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11406
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 10:59:34 (permalink)
    0
    I don't think we're seeing the real code; e.g., example 1 has the cast in the wrong place.
    #8
    NKurzman
    A Guy on the Net
    • Total Posts : 17934
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: online
    Re: Enum with negative member fail 2019/10/16 11:05:23 (permalink)
    +1 (1)
    1and0
    As I understand it, the type of that enum() is an "int". So shouldn't the comparison promote "g_cFaultCode" to an "int"?



    Yes But Post #4, It is already to late, since char is unsigned in XC8.
    it resolves as: if(255 < -2)
     
    char_cFaultCode=0;  //No
    unsigned char_cFaultCode=0;  //Better
    enum PGWFLTCODE r_cFaultCode=0;  //most correct, But is it 8 or 16 bits? ( That depends on the Compiler)
    #9
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11406
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 11:07:51 (permalink)
    +1 (1)
    As the enum type is a quite special type, type casting may or may not result in "correct" sign promotion. Again: an enum is not compatible with s/uint8_t resp. s/uint16_t.

     
    Where in the standard do you see this?
     
    An enumeration is some type of integer than can represent all of the specified values.  That means if there are negative initializers, the enum must be a signed type.  Otherwise, it can be a signed or unsigned type.
    #10
    1and0
    Access is Denied
    • Total Posts : 9882
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 11:19:11 (permalink)
    +1 (1)
    du00000001
    According to my experience (not limited to just gcc), an enum doesn't use more space than necessary. But this may vary between compiler implementations.

    Here are the C89/C90 and C99 standards:
    C90 6.5.2.2, C99 6.7.2.2
    The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.

    And here is XC8 implementation:
    XC8 User's Guide
    The type chosen to represent an enumerated type depends on the enumerated values. A signed type is chosen if any value is negative; unsigned otherwise. If a char type is sufficient to hold the range of values, then this type is chosen; otherwise, an int type is chosen. Enumerated values must fit within an int type and will be truncated if this is not the case.

     
     
     
    du00000001
    The other thing: when promoting an unsigned char to signed int, there might be no sign promotion. (See jtemple's post.)

    All the possible values of an unsigned char can be represented by an int.
     
    Edit: And here is the language standard:
    C99 6.3.1.1
    If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

    post edited by 1and0 - 2019/10/16 11:47:54
    #11
    du00000001
    Just Some Member
    • Total Posts : 3173
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 11:20:26 (permalink)
    +1 (1)
    @ jtemples
    I had a number of mature (read: expensive) compilers that started throwing warnings when assigning enum values to non-enum elements (read: consts, vars) and vice-versa. In C, enums are not exactly "type-proof", but better than just assigning some #define'd values.
     
    P.S.: You have to differentiate "integral value" (a mathematical term denominating some kind of numbers) and "integer value" (the one we're very accustomed to). While these 2 terms seem to be interchangeable, they are not when it comes to enums. Anyway - my experience is from different compiler implementations, not from some standard specification...

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #12
    1and0
    Access is Denied
    • Total Posts : 9882
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 11:25:02 (permalink)
    0
    NKurzman
    Yes But Post #4, It is already to late, since char is unsigned in XC8.
    it resolves as: if(255 < -2)
     
    char cFaultCode=0;

    No, it is:  if (0 > -2)
     
    #13
    1and0
    Access is Denied
    • Total Posts : 9882
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 11:27:28 (permalink)
    0
    jtemples
    I don't think we're seeing the real code; e.g., example 1 has the cast in the wrong place.

    Maybe, but my question in Post #6 still stands.
    #14
    1and0
    Access is Denied
    • Total Posts : 9882
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 12:06:03 (permalink)
    +1 (1)
    Taking a step back, "g_cFaultCode" is an unsigned char and PGWFLT_NO_SLCNET_COMM = -2, so
    if (g_cFaultCode > PGWFLT_NO_SLCNET_COMM)

    should be always true.
    #15
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11406
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Enum with negative member fail 2019/10/16 12:20:24 (permalink)
    0
    "g_cFaultCode" is an unsigned char

     
    I agree, that's likely, but it's possible that it's not (there's a compiler option to make plain char signed).
    #16
    Ian.M
    Super Member
    • Total Posts : 13267
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: online
    Re: Enum with negative member fail 2019/10/16 13:59:08 (permalink)
    +4 (4)
    For <expletive> sake, and your and our sanity! When writing embedded XC C code, put:
    #include <stdint.h>

    immediately after the xc.h include, and any time you *CARE* about the size of an integer type or whether or not a byte is signed, use a C99 Fixed-width integer type.   Even recent XC8 V1.x compilers (or XC8 V2.x in C90 mode) support them.
     
    IMHO, using a char variable to store an arbitrary byte-sized value is a code smell and has been so since the beginning of the millennium.  char is for characters and may or may not be a byte of storage, and  may or may not be signed or unsigned.   All you know and need to know is that it can store one character in the normal character set of the target.

    --
    NEW USERS: Posting images, links and code - workaround for restrictions.
    I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
    #17
    mlp
    boots too small
    • Total Posts : 814
    • Reward points : 0
    • Joined: 2012/09/10 15:12:07
    • Location: previously Microchip XC8 team
    • Status: offline
    Re: Enum with negative member fail 2019/10/17 06:42:18 (permalink)
    0
    Ian.M
    IMHO, using a char variable to store an arbitrary byte-sized value is a code smell and has been so since the beginning of the millennium.

    It has officially been a code smell since 1989.
    It has been off since the first pre-ANSI compiler implemented signed char and unsigned char.
     
    After 30 years I think we can say it's a strong hint the code around it is rotten too.
     
     char is for characters and may or may not be a byte of storage, and  may or may not be signed or unsigned.   All you know and need to know is that it can store one character in the normal character set of the target.

    A-expletive-men.
     

    Mark (this opinion available for hire)
    #18
    jtnum
    Starting Member
    • Total Posts : 44
    • Reward points : 0
    • Joined: 2003/11/07 12:37:02
    • Status: offline
    Re: Enum with negative member fail 2019/10/18 08:00:11 (permalink)
    0
    Here is a follow-up and issue resolved.
    I agree that the code was from legacy from the 1990s and built originally with C18, where char was signed.

    From C18 Getting Started 51295f.pdf

    See “Normally, char defines a variable that has a range from -128 to 127”
     
    Porting to XC8 changed the default treatment of char to unsigned

    From the XC8 User’s Guide DS50002737A

     "The type chosen to represent an enumerated type depends on the enumerated values. A signed type is chosen if any value is negative, unsigned otherwise.  If a char type is sufficient to hold the range of values, then this type is chosen, otherwise, an int type is chosen.  Enumerated values must fit within an int type and will be truncated if this is not the case"
     
    Now for the real cause - Pilot Error when upgrading to XC8
    In the upgrade process to XC8, and version upgrades:
     
    Option categories: Optimization
    WAS Optimization level (!)-9
    IS Optimization level 3
     
    This cured the problem with the original code unchanged, which had casts to (INT).
    Why doesn't XC8 just set a valid default optimization level?
    Maybe it does, and just somehow got corrupted during updates and the copy of original project settings.
     
    Thank you all for your comments! 
     
     
     
    .
     
    #19
    1and0
    Access is Denied
    • Total Posts : 9882
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Enum with negative member fail 2019/10/18 08:14:33 (permalink)
    0
    jtnumata
    This cured the problem with the original code unchanged, which had casts to (INT).
    Why doesn't XC8 just set a valid default optimization level?
    Maybe it does, and just somehow got corrupted during updates and the copy of original project settings.

    Update and fix your code to what Ian and Mark are saying!!!
     
    #20
    Page: 12 > Showing page 1 of 2
    Jump to:
    © 2019 APG vNext Commercial Version 4.5