Multiple of value type vs array

In Arduino, do multiples of the same value type take up more bits than an array with same number of that value type?

In other words:

//Does this
byte a = x;
byte b = y;
byte c = z;

//Take up the same number of bits as this?
byte letter[3] = {x, y , z};

Or does the answer vary based on the value type?

So:

//Maybe this
byte a = x;
byte b = y;
byte c = z;

//Takes up fewer bits than this
byte letter[3] = {x, y, z};

//But this
long a = x;
long b = y;
long c = z;

//Takes up more bits than this?
long letter[3] = {x, y, z};

Any single data type takes the space it takes and multiples take a multiple of that, no matter how they are declared (single or array). So three individual longs take up the same space as an array of long of size 3.

Arrays are a matter of convenience. if I have 256 values, then declaring 256 and referencing variables is a pain, plus you can't use loops to manipulate the data. Arrays are much better in that situation.

int v1;
int v2;
int v3;
int v4;
int v5;
int v6;
int v7;
int v8;

v1 = 3;
v2 = 4;
v3 = 5;
v4 = 6; 
v5 = 7;
v6 = 8;
v7 = 9;
v8 = 10;

Takes up more space than

int v[8];
for (int i=0; i<8; i++) {
  v[i] = i+3;
}

Esepcially with large arrays

Ok thanks. That's what I figured, but I had some hope that there might be a technique similar to packing several true/false values into a single byte.

You can use bytes to store 8 bits (flags).

E.g.

byte flag = 0; //No bits set
flag |= _BV(1); //Set bit 1.

if (flag & _BV(1)){
   //If bit one is true
   flag &= ~_BV(1); //Maybe clear it again
   flag |= (_BV(2)  | _BV(3)); //Set bits 2 and 3.
}
if (flag & (_BV(2) | _BV(3))){
   //If bits 2 and 3 are set
   flag &= ~_BV(2); //Maybe clear bit 2
}

if (!(flag & _BV(2)) && (flag | _BV(3))){
   //If bit 3 is set, and bit 2 isn't
   
}

and so on

WizenedEE:

int v1;

int v2;
int v3;
int v4;
int v5;
int v6;
int v7;
int v8;

v1 = 3;
v2 = 4;
v3 = 5;
v4 = 6;
v5 = 7;
v6 = 8;
v7 = 9;
v8 = 10;



Takes up more space than


int v[8];
for (int i=0; i<8; i++) {
  v[i] = i+3;
}



Esepcially with large arrays

I guess it depends on what you mean by "more space".
Do you think it makes any difference to space taken in SRAM?

I had some hope that there might be a technique similar to packing several true/false values into a single byte

There are for quantities that are less than one byte or word (like the bit flags you are referring to). For example, if you know that a certain value will never exceed 15 (4 bits) then you can pack 2 of those in the hi and low nybble of a byte. Or if a value is 0-7 (3 bits) then 5 can fit in a 16 bit word, etc. This is not automatic, though, and you will need to manage the storage, saving and retrieving through your own code.

It comes down to a tradeoff between execution speed and RAM - if there is enough data that the added complexity would save lots of memory, then it makes sense. Otherwise, for me, ease of understanding (now and in future, when I come back to look at the code) is a higher priority than saving a few bytes.

You can use a struct or union with bitfields to clean up such code.

here's a nice explanation:

BitFields are useful for interpreting irregular data but when used for declaring types they suffer. The elements of a bit field are non-addressable unlike standard struct members. Also due to their definition being implementation defined they are not portable.

I wrote a class not to long ago to create a bit sized boolean style array, I have not completed the hardware that I intended it for so it still remains untested. It allows reading and writing of elements just like an array, also it uses the smallest possible data types for the number of elements ( uint8_t for 256 elements or less, uint32_t for 4294967295 elements ).

BitBool.h

#if defined(ARDUINO) && ARDUINO >= 100
  #include <Arduino.h>
#else
  #include <WProgram.h>
#endif    

template< uint32_t _Items > class BitBool{
  protected:
    template< bool _Flag, typename _True, typename _False > struct If{ typedef _True Result; };
    template< typename _True, typename _False >             struct If< false, _True, _False >{ typedef _False Result; };
    template< uint32_t _A, uint32_t _B >                    struct IsGreaterThan{ static const bool Value = _A > _B; };
    typedef typename If< IsGreaterThan< _Items, 0x100 >::Value, typename If< IsGreaterThan< _Items, 0x10000 >::Value, uint32_t, uint16_t >::Result, uint8_t >::Result INDEX_TYPE;
  private:
    class TemporaryObj{
      public:
        TemporaryObj( const uint8_t u_Idx, uint8_t * const u_Ptr ) : u_Index( u_Idx ), u_Data( u_Ptr ) { return; }
        operator const bool( void ){ return *this->u_Data & ( 1 << this->u_Index ); }
        const bool operator =( const bool b_NewValue )
          {
            if( b_NewValue )  *this->u_Data &= ~( 1 << this->u_Index );
            else              *this->u_Data |= ( 1 << this->u_Index );
            return            b_NewValue;
          }
      protected:
      private:
        const uint8_t    u_Index;
        uint8_t * const  u_Data;            
    };
  public:
    TemporaryObj operator[]( const INDEX_TYPE i_Pos ){ return TemporaryObj( i_Pos & 7, this->u_Data + ( i_Pos >> 3 ) ); }
    uint8_t u_Data[ ( _Items / 8 ) + ( ( ( _Items % 8 ) > 0 ) ? 1 : 0 ) ];        
};
template<> struct BitBool< 0 >{ bool operator[]( const int ){ return false; } };

Sketch

#include "BitBool.h"

//32 elements
BitBool< 32 > b_Data = { 0xFF, 0x00, 0xFF, 0x00 }; //Can preset values.

//75 elements
BitBool< 75 > b_Data1;

void setup( void )
  {
    Serial.begin( 9600 );
    return; 
  }

void loop( void )
  {
    static bool b = false;
    
    if( b = !b ) for( int k = 0 ; k< 512 ; ++k) b_Data[ analogRead( A0 ) ] = analogRead( A1 ) > 512;
    else         for( int k = 0 ; k< 512 ; ++k) Serial.println( b_Data[ k ] ? "True" : "False" );
    return; 
  }

Take note the code compiles but is untested.