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

Is this a C51 / uvision bug?

Hi all
Below is the result of some debugging. I have isolated some code from a bigger project and have put it into a stand-alone project.

I basically don't understand why I can do right bit-shifting and AND'ing on single line, when I can't do left bit-shifting and AND'ing on single line.

If it isn't a bug, then what have I missed?

I have included many comments to describe my problem

#include <ADUC832.H>
#include <string.h>

void main(void) {


char ascii[] = "MC";
unsigned char pdu[3];
int w=0, r=0, len;
char ch1, ch2, rr, rl;


 /*  This is what I want to do:

  while-loop run 1:
     1: Assign to var 'ch1':   ch1 = 'M' (= 0x4D = 0100 1101)
     2: Assign to var 'ch2':   ch2 = 'C' (= 0x43 = 0100 0011)
     3: Assign to var 'w'  :     w = 0
     4: OR together the following:
         ((ch1 >>(w%7))&0x7F) | ((ch2 <<(7-(w%7)))&0xFF);
     <=>     0100 1101        |       1000 0000
     <=>                  1100 1101
     <=>                     0xCD

  while-loop run 2:
     1: Assign to var 'ch1':   ch1 = 'C' (= 0x43 = 0100 0011)
     2: Assign to var 'ch2':   ch2 = 0x00
     3: Assign to var 'w'  :     w = 1
     4: OR together the following:
         ((ch1 >>(w%7))&0x7F) | ((ch2 <<(7-(w%7)))&0xFF);
     <=>     0010 0001        |       0000 0000
     <=>                  0010 0001
     <=>                     0x21

 */

len=strlen(ascii);

while (r<len) {

 // ------ First OR-part  -----------------------
 // -------Both versions below are OK  ----------

      // -- VER 1: OK
      //  ch1 = ascii[r];
      //  rr  = (w%7);
      //  ch1 = (ch1 >> rr) & 0x7F;

      // -- VER 2: OK
        ch1 = (ascii[r] >> (w%7)) & 0x7F;    // Bit-shifting and AND'ing
                                             // may be done in one line

 // ------  Second OR-part  -----------------------------
 //-------  Both versions below are NOT OK ??  ----------

      // -- VER 1: OK
        ch2 = ascii[r+1];
        rl = (7-(w%7));
        ch2 = (ch2 << rl) & ((char)0xFF);    // Bit shift and AND'ing can be
                                             // done in one line, IF type cast
                                             // is used - why?
      //  ch2 = ch2 & 0xFF;                  // If splitting into new line
                                             // type cast is not required?

      // -- VER 2: NOT OK
      //  ch2 = (ascii[r+1] << (7-(w%7))) & 0xFF;  // type cast doesn't help
      //  ch2 = ch2 & 0xFF;  // AND'ing must be on seperate line ?


    //----------------------------------------------------------------
    // IS THIS A BUG ??
    //----------------------------------------------------------------
    // Why can we bit-shift and do the AND'ing in a single line
    // for the first OR-part above, but cannot do it for the second
    // OR-part where bit-shifting and AND'ing must be on two seperate
    // lines ???
    //----------------------------------------------------------------

// ------ Do the actual OR'ing -------
        pdu[w]= (ch1 | ch2) ;

        if ((w%7)==6)
           r++;
        r++;
        w++;
    }
    pdu[w]=0; // terminator

    //----------------------------------------------------------------
    // Run to here in debugger and look at content of
    // local variable 'pdu'.
    // When using 'NOT OK' versions from above
    // pdu will contain {0x4D, 0x21, 0x00}
    // and not {0xCD, 0x21, 0x00} as the 'OK' versions
    // produce.
    //----------------------------------------------------------------

   while(1);

}

Parents
  • "If two cases with the same size of the result react diffrent that IS inconsistent."

    Size isn't the only thing to consider.

    "... that it is inconsistent has nothing whatsoever to do with whatever the manual may say."

    Well, it really does because the manual tells you how operand conversion are applied, factoring in both size and sign. So if we add the detail of how C performs operand conversions to your code fragments, one can see that foo1() and foo3() below are equivalent. Comparing foo1() and foo2() below shows inequality, not inconsistency. Hopefully that has made one of the things people are arguing with you about clearer.

    typedef unsigned char U8;
    typedef unsigned short U16;
    
    U8  GClwdt;
    U8  GClhgt;
    U16 GSloadCnt;
    struct {
        U8 FSLlin;
    } GX_ATT;
    
    void foo1(void)
    {
        GSloadCnt = GClwdt  * GClhgt;
        /* U16    = (int)U8 * (int)U8 */
    
        GSloadCnt = GSloadCnt / GX_ATT.FSLlin;
        /* U16    = U16       / (U16)U8 */
    
        GSloadCnt = GSloadCnt / 2;
        /* U16    = U16       / (U16)int */
    }
    
    void foo2(void)     /* "this (which is the same concatenated)".  IS IT REALLY? */
    {
        GSloadCnt =      (((GClwdt  * GClhgt ) / GX_ATT.FSLlin) / 2);
        /* U16    = (U16)((((int)U8 * (int)U8) / (int)U8      ) / int); */
    }
    
    void foo3(void)
    {
        GSloadCnt = ((     (GClwdt  * GClhgt ) / (U16)GX_ATT.FSLlin) / 2);
        /* U16    = (((U16)((int)U8 * (int)U8) / (U16)U8           ) / (U16)int); */
    }
    
    
    

Reply
  • "If two cases with the same size of the result react diffrent that IS inconsistent."

    Size isn't the only thing to consider.

    "... that it is inconsistent has nothing whatsoever to do with whatever the manual may say."

    Well, it really does because the manual tells you how operand conversion are applied, factoring in both size and sign. So if we add the detail of how C performs operand conversions to your code fragments, one can see that foo1() and foo3() below are equivalent. Comparing foo1() and foo2() below shows inequality, not inconsistency. Hopefully that has made one of the things people are arguing with you about clearer.

    typedef unsigned char U8;
    typedef unsigned short U16;
    
    U8  GClwdt;
    U8  GClhgt;
    U16 GSloadCnt;
    struct {
        U8 FSLlin;
    } GX_ATT;
    
    void foo1(void)
    {
        GSloadCnt = GClwdt  * GClhgt;
        /* U16    = (int)U8 * (int)U8 */
    
        GSloadCnt = GSloadCnt / GX_ATT.FSLlin;
        /* U16    = U16       / (U16)U8 */
    
        GSloadCnt = GSloadCnt / 2;
        /* U16    = U16       / (U16)int */
    }
    
    void foo2(void)     /* "this (which is the same concatenated)".  IS IT REALLY? */
    {
        GSloadCnt =      (((GClwdt  * GClhgt ) / GX_ATT.FSLlin) / 2);
        /* U16    = (U16)((((int)U8 * (int)U8) / (int)U8      ) / int); */
    }
    
    void foo3(void)
    {
        GSloadCnt = ((     (GClwdt  * GClhgt ) / (U16)GX_ATT.FSLlin) / 2);
        /* U16    = (((U16)((int)U8 * (int)U8) / (U16)U8           ) / (U16)int); */
    }
    
    
    

Children
  • below shows inequality, not inconsistency

    you can keep your verbiage with my blessing, just acceot that it is yours instead of insisting that i accept it. Since every statement figures out a short it is inconsistent that they do not work on the longest thing in the equation.

    because the manual tells you
    here we go again, documenting an inconsistency does NOT make it anything else

    Erik

  • Oh brother! You didn't even look at the differences to see that they are flat out obviously different -- what effect the presence and absence of your single (U16) had in other subexpressions. I honestly though that boiling how the conversions are performed to a low gravy would benefit you, but you're just a hopeless case, I'm afraid -- pure and simple.

    You can lead people to knowledge, but you can't make them think.