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

Integral Promotion

We are currently in the process of evaluating Keil tools for possible purchase. Using the evaluation package, I have been checking some common functions. One of them is a simple bit test macro suitable for a large variable where speed is not important.

#define BTST(VAR, BITPOS) ((VAR) & (1<<(BITPOS)))

I used this in the following manner

unsigned long temp;
unsigned char shift;

BTST(temp, shift);

The Keil C51 compiler generates the following:


MOV A,#01H
MOV R6,#00H
MOV R0,shift?143
INC R0
SJMP ?C0015
?C0014:
CLR C
RLC A
XCH A,R6
RLC A
XCH A,R6
?C0015:
DJNZ R0,?C0014
MOV R7,A
MOV A,R7
ANL A,temp?144+03H
MOV R7,A


Note that even though I have ANSI promotions enabled, it does not promote the unsigned character to a long. It appears to promote it to an integer (using A and R6 for the data), but then never uses the MSB (R6) when performing the AND operation.

I have even tried this:
BTST(temp, (unsigned long) shift);

and I get the same results.

I have used this macro with many other compilers with complete success, following what I understand about integral promotion in ANSI C.

There seem to be several threads about bit-fields and the like, but none seemed to deal with integers or longs or shift operations.

Any thoughts?

Thanks much in advance,

Peter

  • Hi Peter,

    The 'unsigned char shift' doesnt need to be promoted to a long because it is just used to generate a mask '2**shift' internaly by the compiler and as such 'shift' should not exceed 31 (for a 32bit no.).
    If anything it doesnt look like the compiler is generating a 4 byte mask so it might be better to try and cast VAR as long in your macro (but this will be inefficient for char/int variables) to ensure that it works thus,
    #define BSTS(VAR, BITPOS) ( ((unsigned long)VAR) & (1 << BITPOS) )

    Hope this helps,
    Mark.

  • There are several problems with your test code.

    1. BTST(temp, shift);

    This does nothing with the results. Therefore, the compiler does not have to generate any code at all since no variables are affected!

    2. The size of an int in the Keil compiler is 16 bits. With ANSI integer promotion enabled, here's what happens in the MACRO:

    A. BTST(temp, shift) is expanded into

    ((temp) & (1<<(shift))

    B. 1<<(shift) is evaluated first. 1 is promoted to an integer (16-bit) and is shifted left shift times. Remember that shift is an unsigned char.

    C. temp (which is an unsigned long) is ANDed with the result of step B (which is promoted from an integer to an unsigned long).

    D. The results of the AND are not stored anywhere so the code generated doesn't have anything to do with the results of the AND operation.

    3. If other compilers generate code that works just fine, you may want to check the size of an integer. If it is 32 bits, then that explains why this example works on other compilers.

    4. The following altered example will do what you want:

    #define BTST(VAR, BITPOS) ((VAR) & (1L<<(BITPOS)))
    
    void main (void)
    {
    unsigned long temp;
    unsigned char shift;
    volatile unsigned long junk;
    
    junk = BTST(temp,shift);
    
    while (1);
    }

    Jon

  • Firstly, I apologize for including only a code snippet that could not be directly plugged into the compiler. Of course, the details I omitted were critical, thanks for showing me how to get this to work.

    The result that I was storing into was character length. The compiler was optimizing out the unneeded bytes. I hadn't even noticed this (I was thinking the result was a long) until your message made me look over the code again.

    I would also like to say that although the result of this exercise was a stupid mistake on my part, it wasn't a total waste of anyone's time as it has shown the support group on this message board to be execellent, which is also a critical part of evaluating these tools we are considering purchasing.

    I look forward to posting more stupid questions...

    Thanks Mark and Jon,
    Peter

  • I look forward to posting more stupid questions...

    And I'm sure there are many of us who look forward to answering them.
    ;-)

    Seriously, though. Thanks for the thanks.

    Jon