Alignment

I'm just wondering about data boundaries, as i'm only familiar with c1.exe

does gcc allow boundary changes like #pragma pack( 1 ). I assume not as an 8-bit processer is probably locked into 1 byte boundaries.

But just in case it could be a 2-byte or greater boundary, I thought I better ask.

I have found some avr code using #pragma pack but I know many pragma codes are microsoft specific, so gcc may just ignore it.

Cheers.

It's an 8-bit processor, and I am not familiar with any advantages to be gained by moving alignments to word boundaries. So I wouldn't bother with the pack pragma.

I agree fully, I just would like to verify the boundary. from your answer I take it that the boundary is less than a WORD ie byte.

My query was in relation to bit fields and if this code is guaranteed to be 1 byte. EDIT Or not padded when used as a class data member

typedef unsigned char byte;

class Byte{
    
    public:
    
      Byte( void ){ *( byte* )( this ) = NULL; return; };
      Byte( const byte b_Bit8, const byte b_Bit7, const byte b_Bit6, const byte b_Bit5, const byte b_Bit4, const byte b_Bit3, const byte b_Bit2, const byte b_Bit1 ) : b_1( b_Bit1 ), b_2( b_Bit2 ), b_3( b_Bit3 ), b_4( b_Bit4 ), b_5( b_Bit5 ), b_6( b_Bit6 ), b_7( b_Bit7 ), b_8( b_Bit8 ){ return; };
      Byte( const Byte &b_Ref ){ *( byte* ) this = ( byte& ) b_Ref; return; };
      Byte( const byte b_Val ){ *( byte* ) this = b_Val; return; };
      
      operator byte&(){ return *( byte* )( this ); };
      
      Byte &operator =( const byte b_Data ){ ( ( byte& ) *this ) = b_Data; return *this; };

      byte b_1 : 1;
      byte b_2 : 1;
      byte b_3 : 1;
      byte b_4 : 1;
      
      byte b_5 : 1;
      byte b_6 : 1;
      byte b_7 : 1;
      byte b_8 : 1;
      
    protected:
    private:
  };

pYro_65:
I agree fully, I just would like to verify the boundary. from your answer I take it that the boundary is less than a WORD ie byte.

I don't personally regard a word and a byte as being synonyms.

Also I wouldn't use "bit" alignments. I think the code generated will be lengthier than normal.

I'm not implying anything about bytes or words. What I wanted to know is if the arduino runs on a 1 byte boundary. As in class data members will not be padded to correctly align them.

pYro_65:
As in class data members will not be padded to correctly align them.

What is the problem you are really trying to solve here? Why do you want to know that?

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

I have no problem, I need to know this to construct my code properly, it shouldn't be such an 'unmentionable' topic as it seems here.

lets just whip up an example

struct mystruct{
  int a;
  char b;
  bool c;
};

This structure under 1-byte alignment would occupy 5 bytes assuming int is 16-bit.
Under 2-byte alignment. this structure would occupy 6 bytes as a padding byte would be inserted after 'char b' to ensure 'bool c' starts on a 2-byte boundary.

I have no problem, I need to know this to construct my code properly, it shouldn't be such an 'unmentionable' topic as it seems here.

It's not unmentionable, I am wondering why you are asking if you have "no problem". Perhaps if you explained why it is important?

This structure under 1-byte alignment would occupy 5 bytes assuming int is 16-bit.

How about testing before making these claims?

struct mystruct{
  int a;
  char b;
  bool c;
};

void setup ()
{
  Serial.begin (115200);
  Serial.println ();
  Serial.println (sizeof (mystruct));
}

void loop (){}

Output: 4

The int takes 2, the char 1, and the bool 1.

Forget the alignment unless you can show why it is important.

Well thats a simple error on my part, I assumed also that bool is two bytes like many other c++ implementations. Exactly my point of asking this question... So I don't have to assume things.

one major player in alignment is backwards compatibility. Found in the Win API transition from 16-bit to 32-bit then to 64-bit.

structures passing data to functions have been extended and these are required to be in certain alignments to be usable by both old and new code. by using the structure size, a version type can be established. With no default alignment the structures could vary in size resulting in the wrong execution of code.

I know windows and any other implementation is unrelated to what could be in the arduino, this is just an example.

As your sketch output was 4 bytes, I'm still assuming its a 1 byte boundary, the char and bool still sit side by side in a 2-byte alignment. I guess I'll do up my own sketch with an extra few variables to enforce padding if it exists.

Thanks for the input anyway. I still want to find a definitive answer as knowing it will benefit me in the future. I have only just started with arduino 4 weeks ago so I'm simply trying to understand it as much as possible.

gcc doesn't support the pack pragma. Here's how you do it with gcc, taken from some filesystem code I wrote:

struct Mbr {
  uint8_t code[440];
  uint32_t diskSignature;
  uint16_t reserved1;
  MbrPartition partitions[4];
  uint16_t signature;
} __attribute__ ((packed));

thanks Andy I'll look into the attribute modifier, might have some useful options.

I was curious about this too, so I wrote a little sketch to try things out:

#include <Arduino.h>
#include <stddef.h>


#define PAD0
#define PAD1 char pad0;
#define PAD2 char pad0; char pad1;
#define PAD4 char pad0; char pad1; char pad2; char pad3;
#define PAD8 char pad0; char pad1; char pad2; char pad3; char pad4; char pad5; char pad6; char pad7;

#define TEST_PAD(type, name, pad) \
    { \
        struct Test ## pad ## _ ## name { PAD ## pad; type target; }; \
        Test ## pad ## _ ## name t ## pad; \
        Serial.print(F(#type " -- pad " #pad " -- size ")); \
        Serial.print(sizeof(t ## pad)); \
        Serial.print(F(" -- offset ")); \
        Serial.println( offsetof(Test ## pad ## _ ## name, target) ); \
    }

#define TEST(type) \
    TEST_PAD(type, type, 0); \
    TEST_PAD(type, type, 1); \
    TEST_PAD(type, type, 2); \
    TEST_PAD(type, type, 4); \
    TEST_PAD(type, type, 8);
#define TESTN(type, name) \
    TEST_PAD(type, name, 0); \
    TEST_PAD(type, name, 1); \
    TEST_PAD(type, name, 2); \
    TEST_PAD(type, name, 4); \
    TEST_PAD(type, name, 8);


void f() {};
class C_simple {
    public:
        C_simple() {};
        void f() {};
};
class C_vtable {
    public:
        C_vtable() {};
        virtual void f() {};
        virtual ~C_vtable() {};
};
typedef void (*pfunc)();
typedef void (C_simple::* pmf_C_simple)();
typedef void (C_vtable::* pmf_C_vtable)();


void setup() {
    const __FlashStringHelper *blank = F("");
    Serial.begin(57699);
    Serial.println(F("----------------------- BOOTED -----------------------"));
    TEST(uint8_t); Serial.println(blank);
    TEST(uint16_t); Serial.println(blank);
    TEST(uint32_t); Serial.println(blank);
    TEST(uint64_t); Serial.println(blank);

    TEST(float); Serial.println(blank);
    TEST(double); Serial.println(blank);

    TEST(bool); Serial.println(blank);
    TEST(char); Serial.println(blank);
    TEST(byte); Serial.println(blank);
    TEST(word); Serial.println(blank);

    TEST(int); Serial.println(blank);
    TEST(short); Serial.println(blank);
    TEST(long); Serial.println(blank);
    TESTN(long long, longlong); Serial.println(blank);

    TESTN(int*, pointer); Serial.println(blank);
    TEST(size_t); Serial.println(blank);

    TEST(pfunc); Serial.println(blank);
    TEST(pmf_C_simple); Serial.println(blank);
    TEST(pmf_C_vtable); Serial.println(blank);
}


void loop() {
    // everything interesting has already been done
}

Interpretting the output it does indeed look like an 8bit processor, with 2 byte pointers and 4 byte pointer to member functions.

I was curious if I could squeeze some compiler-generated padding out of my datastructures by reordering the members, but it looks like there isn't much to do. (Hmmm... except squash booleans into bits of a single field.)

Backward compatibility. What about the sideways compatibilities?

What about the sideways compatibilities?

What about comprehensibility? There is a special place in hell reserved for macro writers.

drewfish:
I was curious if I could squeeze some compiler-generated padding out of my datastructures by reordering the members, but it looks like there isn't much to do. (Hmmm... except squash booleans into bits of a single field.)

That's funny, as I think I made this thread to verify some points for my BitBool class ( posted 2 years ago ), of which the beginnings appear above. The result of which is located here: BitBool Class ( boolean array ), upto 16000 elements on UNO. - Libraries - Arduino Forum The library has evolved twice since this version but it still works fine.

PaulS:

What about the sideways compatibilities?

What about comprehensibility? There is a special place in hell reserved for macro writers.

Where they have to debug tons of that kind of code without any help and a boss down their neck?

Hehe... yeah I agree that macros such as I posted here are a really bad idea for any code that is intended to be maintained. The code I posted wasn't intended to be maintained, but just a quick one-off to gather real-world info on data type sizes and alignments. Sorry, I won't inflict my cleaver macros on y'all again :slight_smile:

(BTW I think simple macros do have their place. For example the Arduino API has quite a few.)

drewfish:
(BTW I think simple macros do have their place. For example the Arduino API has quite a few.)

I Agree, however rendering valuable names in every namespace unusable was a terrible choice ( Arduino API ).
I'm sure somebody may want a class with members called min, or max.

Or at least the possibility of overloading them ( if they were a real function ).

I had a problem today on the Due... after hours tracked it down to a struct. The last field was a "byte" and instead of the size being 21... it was 24.

As it was a header for a file... when I read it in it was reading 3 too many and after that... all hell broke loose.

Using the packed attribute fixed it.

I will give a very good reason for alignment
I am currently looking at this very issue because I need to pass binary data to an STM32 from an Arduino Nano over i2c interface, there is a problem with different size records due to the crazy way word is defined in the C language
I also have to pass this data via UDP to a Pascal program and I spent the day massaging records to get the mess to align
It took mere seconds in Pascal to ensure a packed record

On small devices with a mere 20k of ram, size matters