Data Type - One Bit

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Does GCC have a Data Type of 1 bit? Can you make Arrays of Bits?

I only see this in the AVR-lib C User Manual:

Quote:

• Data types:
char is 8 bits, int is 16 bits, long is 32 bits, long long is 64 bits, float and
double are 32 bits (this is the only supported floating point format), pointers
are 16 bits (function pointers are word addresses, to allow addressing up to 128K
program memory space). There is a -mint8 option (see Options for the C
compiler avr-gcc) to make int 8 bits, but that is not supported by avr-libc and
violates C standards (int must be at least 16 bits). It may be removed in a future
release.

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nope but a lot of folks cast an eight member bit field onto GPIOR0 (in all recent AVRs) to give them 8 "bit variables" that have fast, atomic access with SBI and CBI - search "bitfield GPIOR0" for lots of prior traffic about this.

Cliff

EDIT: this is just one of the hits:

https://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want to have variables that only occupy a single bit, you can do this type of thing:

typedef struct
{
  unsigned char TransmitBusy  : 1 ;
  unsigned char DoXonXOff     : 1 ;
  unsigned char XOffHold      : 1 ;
  unsigned char LastCharHadMP : 1 ;
  unsigned char MessageRead   : 1 ;
  unsigned char BadMessage    : 1 ;
  unsigned char LinkBusy      : 1 ;
  unsigned char CommsError    : 1 ;
} CommsLineStatus ;

IIRC you may need to be careful (i.e. not rely on) the order of the bits. The order on the AVR target does not match the order on GCC code that we compile for Renesas H8s.

A

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Andy,

As shown in that thread I linked. Just typedef'ing the bit-field is only half the story. The key thing is then casting this onto an address in the 0x00..0x1F I/O space so that CBI/SBI are then used. (GPIOR0 is good for this on "new" AVRs while I've used TWAR on an older mega16 which is a useful 8 bit R/W register)

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Cliff - didn't know about the efficiency thing.

However, if one is not particularly worried about efficiency, but are simply saving RAM, (a situation that we find we are in on many projects) the above example does actually generate code that occupies only a single bit per variable.

Cheers
A

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndyG wrote:
If IIRC you may need to be careful (i.e. not rely on) the order of the bits. The order on the AVR target does not match the order on GCC code that we compile for Renesas H8s.

The Renesas is big endian?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Despite the quote from the avr-libc manual in the OP, this is a general C language question and really should be addressed in the main AVR Forum. There is really nothing GCC specific about this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
The Renesas is big endian?
Yes, but even if you have a collection of bits in a single byte, you cannot rely on the bit order (I believe.)

Of course, this may be a consequence of the high end/ low end nature of the CPU.

A

If we are not supposed to eat animals, why are they made out of meat?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, I guess the AVR bitfields could go either way because the hardware is non-endian. The compiler allows multibyte operands so it gets to decide for itself which endianness to use.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In C, no, the best you can is are macros or inline functions to access bits.

In C++ of course you can:

#include 

template  struct sizeType;

template <> struct sizeType {
  typedef uint32_t type;
};

template <> struct sizeType {
  typedef uint16_t type;
};

template <> struct sizeType {
  typedef uint8_t type;
};

class BitProxy {
  uint8_t& data;
  uint8_t const bit;
  BitProxy(uint8_t& data1,  uint8_t bit1) : data(data1), bit(bit1) {}
  template  friend class BitArray;
 public:


  operator bool () const {
    uint8_t result = data & bit;
    return result;
  }

  template  operator T () const { return bool(*this); }
  bool operator ! () const { return !bool(*this); }
  bool operator == (bool b) const { return bool(*this) == b; }
  bool operator != (bool b) const { return bool(*this) != b; }
  bool operator ^  (bool b) const { return bool(*this) ^ b; }

  BitProxy& operator = (bool a) { 
    if (a) data |= bit; else data &= ~bit;
    return *this;
  }

  BitProxy& operator |= (bool a) { 
    if (a) data |= bit;;
    return *this;
  }

  BitProxy& operator &= (bool a) { 
    if (!a) data &= ~bit;
    return *this;
  }

  BitProxy& operator ^= (bool a) { 
    data ^= bit;
    return *this;
  }
};

template  class BitArray {
  uint8_t data[(size + 7) / 8];
 public:

  typedef typename sizeType<(size > 0xFFUL), (size > 0xFFFFUL)>::type SizeType;

  BitProxy operator [] (SizeType index) {
   return BitProxy(data[index / 8], 1 << (index % 8));
  }

  const BitProxy operator [] (SizeType index) const {
   return BitProxy(const_cast(data[index / 8]), 1 << (index % 8));
  }

};

Use it like this:

#include 

BitArray<40> test;

bool demo() {
  test[10] = 1;
  test[20] = 1;
  return test[17];
}


void demo2() {
  if (test[22]) printf("Hello\n");
}

uint8_t demo3() {
  return test[30];
}

int i;

uint8_t demo4(const BitArray<40>& test) {
  return test[i];
}

You may be able to improve writing non-constant values into bits. This example does not implement a bit iterator (like a pointer).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TimothyEBaldwin wrote:
In C, no, the best you can is are macros or inline functions to access bits.

In C++ of course you can... vast amount of code follows

:shock: Egad! Isn't this a little like trying to kill a mosquito with a tactical nuclear warhead?

In the end, does the compiler generate the same code in this C++ case as the far simpler C solution? Somehow I doubt it, although I could be mistaken.

This seems to me to be a perfect example of why every application and OS takes ever larger amounts of RAM and ever faster processors just to stay even with where they were just a few years ago. I'll admit, I'm a fan for abstracting information, but ye gods!

(*pant! pant! pant!* Okay, I'm calming down now. :evil:)

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stu_san wrote:
In the end, does the compiler generate the same code in this C++ case as the far simpler C solution?

Actually yes - unless you have optimisation disabled.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TimothyEBaldwin wrote:
stu_san wrote:
In the end, does the compiler generate the same code in this C++ case as the far simpler C solution?

Actually yes - unless you have optimisation disabled.

Cool. I'm happy the compiler can see through the obfuscation.

Sorry for the flame -- bad hair day I guess.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!