6
\$\begingroup\$

I have the following code in my microcontroler program:

int analogValue = ADCH;        // ADC Data Register

//
// Simple analog comparator. 
// If analogValue lower than threshold then toggle output high,
// Otherwise toggle it low.
//
if ( analogValue > 128 ) {
    PORTB = 0;                 // Port B Data Register
} else {
    PORTB = _BS( outputPin );  // Port B Data Register
}

Where:

  • ADCH is the register that contains the value from the ADC
  • PORTB is a dital output port that toggles an LED

Looking at the resulting assembly code, I noticed that it is doing a 16 bit compare (lines 40-44) where strictly speaking only 8 bits would have been sufficient:

40:   90 e0           ldi     r25, 0x00       ; 0
42:   81 38           cpi     r24, 0x81       ; 129
44:   91 05           cpc     r25, r1
46:   14 f0           brlt    .+4             ; 0x4c <__SREG__+0xd>
48:   18 ba           out     0x18, r1        ; PORTB
4a:   f5 cf           rjmp    .-22            ; 0x36 <__CCP__+0x2>
4c:   28 bb           out     0x18, r18       ; PORTB
4e:   f3 cf           rjmp    .-26            ; 0x36 <__CCP__+0x2>

I realize I declared analogValue as int, which indeed is 16 bit on AVR, but ...

How can I instruct the compiler to use 8 bit comparison? The Arduino IDE allows me to use byte, but avr-gcc by default doesn't.

Check this page for the complete program and its disassembled resulting code.

EDIT1:

Changing int to char changes the assembly code to:

14:   11 24           eor     r1, r1          ; r1 = 0
3e:   18 ba           out     0x18, r1        ; PORTB

Basically skipping the test entirely.

EDIT2: (Thnx: Wouter van Ooijen)

Changing int to unsigned char changes the assembly code to:

3c:   85 b1           in      r24, 0x05       ; ADCH
3e:   ...
40:   87 fd           sbrc    r24, 7          ; compare < 128 (well optimized)
42:   02 c0           rjmp    .+4             ; 0x48 <__SREG__+0x9>
44:   18 ba           out     0x18, r1        ; 24
46:   f7 cf           rjmp    .-18            ; 0x36 <__CCP__+0x2>
48:   98 bb           out     0x18, r25       ; 24
4a:   f5 cf           rjmp    .-22            ; 0x36 <__CCP__+0x2>
\$\endgroup\$

2 Answers 2

18
\$\begingroup\$

I actually think a better practice that avoids this architectural ambiguity is to include <stdint.h> then use declarative types like:

  • uint8_t for unsigned 8-bit integers
  • int8_t for signed 8-bit integers
  • uint16_t for unsigned 16-bit integers
  • uint32_t for unsigned 32-bit integers

and so on...

\$\endgroup\$
5
  • \$\begingroup\$ This appears to work (checked the assembly code again). Wasn't familiar with these types at all. Where does the _t come from? \$\endgroup\$
    – jippie
    Commented Jul 7, 2012 at 20:01
  • 3
    \$\begingroup\$ _t indicates, conventionally, that its naming a type \$\endgroup\$
    – vicatcu
    Commented Jul 7, 2012 at 20:25
  • 3
    \$\begingroup\$ These are standard fixed width integer types, introduced in C99. You may need to #include <stdint.h>. en.wikipedia.org/wiki/C_data_types#Fixed_width_integer_types \$\endgroup\$ Commented Jul 7, 2012 at 23:01
  • 2
    \$\begingroup\$ +1. I use this to remove any ambiguity and for ultimate portability \$\endgroup\$
    – Jon L
    Commented Jul 8, 2012 at 2:05
  • \$\begingroup\$ A danger when using such types is that expression types are often non-portable in surprising ways. For example, on a system where int is 16 bits, given uint32_t flag;, the statements flag &= ~0x00004000; and flag &= ~0x00010000; will behave as expected, but flag &= ~0x00008000; will behave rather differently. \$\endgroup\$
    – supercat
    Commented Jan 22, 2015 at 21:45
8
\$\begingroup\$

The more-or-less standard definition of a byte in C is 'unsigned char'.

\$\endgroup\$
2
  • \$\begingroup\$ Ah the unsigned part did the job, char on it's own compiles without warnings. \$\endgroup\$
    – jippie
    Commented Jul 7, 2012 at 18:23
  • 1
    \$\begingroup\$ A famous C 'gotcha' is that the compiler is free to interpret 'char' as either 'signed char' or 'unsiged char', so the effective range of plain 'char' that you can count on is 0..127. Use plain 'char' only for 7-bit ASCII, never for anything else. \$\endgroup\$ Commented Jul 7, 2012 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.