This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

__inline and change of sign warning

Hi all,

I would like to discover why the compiler issues warning #68 (integer conversion resulted in a change of sign) for the code below. It is issued only for -O3, "Optimize for Time" enabled and when the function is inlined (__inline keyword).

I have tried to cast anything which could be implicitly converted to int back to uint, but no chance to get rid of this warning.

armcc.exe V4.0.0.524

static __inline uint8_t IsDecDigit(char c)
{
    return (   (c >= '0')
            && (c <= '9'));
}

...

static void UseIt(void)
{
    char *name;
    ...
    /* Initialize the name to something useful */
    ...
    if (   (IsDecDigit(name[3])) /* <- warning issued for this expression */
        && (IsDecDigit(name[4]))
        && (IsDecDigit(name[5]))
        && (IsDecDigit(name[6]))
    {
        ...
    }
}

Thanks for responses.

Regards Pavel

Parents
  • Hans,
    I would say I understand implicit conversions also as integer constants. Anyway thanks for explanation ;)

    What do I not understand is the fact there are cases the compiler decides to issue the warning also as cases it does not. The conversions you mentioned are performed always, aren't? Why inlining code affects this?

    Also I don't care whether it's a problem from the code point of view (because it's not). My only concern is the warning issuing.

    It seems the point is rather in the place of function call (uint8_t && uint8_t) rather than in the function body. Anyway, would you say there are any implicit conversions I missed in the code below, which could cause the sign changes?

    static __inline int IsDecDigit(char c)
    {
        return (int)((   (c >= (char)'0')
                      && (c <= (char)'9')) ? 1 : 0);
    }
    
    ...
    if (IsDecDigit(name[5])) /* OK */
    {
       ...
    }
    ...
    if (   (IsDecDigit(name[5])) /* (int && int) <- warning */
        && (IsDecDigit(name[6])))
    {
       ...
    }
    
    

    Regards Pavel

Reply
  • Hans,
    I would say I understand implicit conversions also as integer constants. Anyway thanks for explanation ;)

    What do I not understand is the fact there are cases the compiler decides to issue the warning also as cases it does not. The conversions you mentioned are performed always, aren't? Why inlining code affects this?

    Also I don't care whether it's a problem from the code point of view (because it's not). My only concern is the warning issuing.

    It seems the point is rather in the place of function call (uint8_t && uint8_t) rather than in the function body. Anyway, would you say there are any implicit conversions I missed in the code below, which could cause the sign changes?

    static __inline int IsDecDigit(char c)
    {
        return (int)((   (c >= (char)'0')
                      && (c <= (char)'9')) ? 1 : 0);
    }
    
    ...
    if (IsDecDigit(name[5])) /* OK */
    {
       ...
    }
    ...
    if (   (IsDecDigit(name[5])) /* (int && int) <- warning */
        && (IsDecDigit(name[6])))
    {
       ...
    }
    
    

    Regards Pavel

Children
  • Just my opinion: I cannot see how this warning could be justified. Neither in the original code example, nor in the 'new and improved' version. Hans cited some possible explanations, but I think they are too far-fetched. For example, 'changed signedness' and 'changed sign' is not the same.
    We could just call it a benign compiler bug and leave it at that. Hopefully, it doesn't lead to generation of incorrect object code.

  • I believe this is a spurious warning and is fixed the the compiler version included with MDK 4.10 and later. See also <http://www.keil.com/update/relnotes/MDK411.htm> (although this issue is not discussed there).

  • Hans cited some possible explanations, but I think they are too far-fetched. For example, 'changed signedness' and 'changed sign' is not the same.

    You incorrectly assume I wasn't aware of this difference. And your characterization of the explanation as "too far fetched", let me point out it pretty much has to be that complicated, simply because the stated combination of causes is, too.

    The crucial clues are that that warning is about an actual change of sign, not just of signedness, and that it only occurs if the compiler is asked to fully optimize that inline function

    I'm still quite sure that that happens because only in this combination of code features and optimization flags the compiler detects that the change of signedness actually turns into a change of sign. That can happen because a particular char argument to that inline function is found to be a large enough positive number to yield a negative number after conversion to 'char'.

  • I'm still quite sure that that happens because only in this combination of code features and optimization flags the compiler detects that the change of signedness actually turns into a change of sign. That can happen because a particular char argument to that inline function is found to be a large enough positive number to yield a negative number after conversion to 'char'.

    Now I see it. If the contents of name[] are known at compile time, the compiler may be able to detect a change of sign in the calculations. Seeing a more complete code sample could clarify this too.
    Spot on, on all points. Sorry for the noise.

  • As I see it now, I would rather agree it's just a compiler bug as mentioned somewhere above...
    Anyway, there is complete and completely useless example you want ;)
    Use the compiler settings mentioned earlier.

    #include <stdint.h>
    #include <lpc23xx.h>
    
    /*
     * Set to nonzero to remove warnings ;)
     */
    #define REMOVE_WARNINGS 0
    
    static char *random_data = (char *)0x40000000;
    
    
    /*
     * Remove __inline and warnings disappear
     */
    
    
    static __inline int IsDecDigit(char c)
    {
        return (int)((   (c >= (char)'0')
                      && (c <= (char)'9')) ? 1 : 0);
    }
    
    
    static __inline int IsSet(uint32_t flags, uint8_t pos)
    {
        return (int)((int)(flags & (1ul << pos)) ? 1 : 0);
    }
    
    
    static DoSomething(uint8_t what)
    {
        FIO0CLR = (1ul << what);
    }
    
    
    static DoSomethingElse(uint8_t what)
    {
        FIO1SET = (1ul << what);
    }
    
    
    int main(void)
    {
        char     *name  = random_data;
        uint32_t  flags = 0;
    
    #if REMOVE_WARNINGS /* Not sure why..., maybe compiler chooses different optimization when there is inline asm? */
        __asm("nop");
    #endif
    
        for (;;)
        {
            if (IsDecDigit(name[0]))
            {
                DoSomething(1);
                flags |= (1ul << 0);
            }
    
            if (   IsDecDigit(name[1])   /* warning:  #68-D: integer conversion resulted in a change of sign */
                && IsDecDigit(name[2]))
            {
                DoSomething(2);
                flags |= ((1ul << 1) | (1ul << 2));
            }
    
            if (IsSet(flags, 3))
            {
                DoSomethingElse(3);
            }
    
            if (   IsSet(flags, 4)       /* warning:  #68-D: integer conversion resulted in a change of sign */
                && IsSet(flags, 5))
            {
                DoSomethingElse(5);
                flags |= 0xf;
            }
        }
    
    /*    return 0;*/
    }