Smallest unit in memory

What is the smallest variable available?
I know that boolean is NOT because in backend, hardware side, there is a minimum of memory allocation. So my guess would be eithier Byte or Int (4 byte).

You can use the bit-wise boolean operators “|”, “&”, and “^” to store multiple boolean values in a byte, treating the byte like an array of eight boolean values. But the smallest unit of memory to which you can assign a name? That’s a byte or a char or an unsigned char. 8 bits. OK, we all knew that. But is there any actual memory saving over using two named longs over two named characters. Does everything get assigned a minimum of 32 bits, all named variables starting on the 32-bit word barrier. Do these declarations each actually consume the same amount of RAM?

char a, b; // 8 bits each
short int c, d; // 16 bits each
short int arrayC[2], arrayD[2]; // 32 bits each
int e, f; // 32 bits each
long g, h; // 32 bits each
char arrayA[3], abbayB[3]; // 24 bits each
char arrayC[4], abbayD[4]; // 32 bits each

Sorry that I won’t answer this question direct, but there would be an easy way to find out by printing out the &a, &b, &c, … memory locations of the variables (r.g. Serial.println((uint32_t)&a, HEX);.
I would have done this myself and posted my results, but I haven’t got my Core at hand at the moment :frowning:

1 Like

Yes, I’m busy doing that myself. Too curious to wait for the knowledgable. And the good natured :slight_smile:

1 Like

This:

char a, b; // 8 bits each
short int c, d; // 16 bits each
short int aC[2], aD[2]; // 32 bits each
int e, f; // 32 bits each
long g, h; // 32 bits each
char arrayA[3], arrayB[3]; // 24 bits each
char arrayC[4], arrayD[4]; // 32 bits each

char sbuf[80];

void setup() {
  sprintf( sbuf, "%s", __TIME__);
  Spark.publish( "minalloc", sbuf);
  
  sprintf( sbuf, "chars %u %u - shorts %u %u", (char *)&a, (char *)&b, (char *)&c, (char *)&d);
  Spark.publish( "minalloc", sbuf);
  sprintf( sbuf, "ints %u %u - longs %u %u", (char *)&e, (char *)&f, (char *)&g, (char *)&h);
  Spark.publish( "minalloc", sbuf);
  sprintf( sbuf, "2shorts %u %u - 3chars %u %u", (char *)&aC, (char*)&aD, (char *)arrayA, (char *)arrayB);
  Spark.publish( "minalloc", sbuf);
  
  delay(3000); // publish delay

  sprintf( sbuf, "%u %u", (unsigned long)&b-(unsigned long)&a, (unsigned long)&d-(unsigned long)&c);
  Spark.publish( "minalloc", sbuf);
  sprintf( sbuf, "%u %u", (unsigned long)&f-(unsigned long)&e, (unsigned long)&h-(unsigned long)&g);
  Spark.publish( "minalloc", sbuf);
  sprintf( sbuf, "%u %u", (unsigned long)aD-(unsigned long)aC, (unsigned long)arrayB-(unsigned long)arrayA);
  Spark.publish( "minalloc", sbuf);
}

void loop() {
    delay(1000);
}

renders this:

09:25:04
chars 536873564 536873565 - shorts 536873566 536873568
ints 536873572 536873576 - longs 536873580 536873584
2shorts 536873588 536873592 - 3chars 536873596 536873599
1 2
4 4
4 3
3 Likes

TL;DR conclusions? :smile:

1 Like

By looking at the adresses printed (which is standard: a byte per block) we can see that a byte actually use one byte of memory only. and short, 2, int takes 4, long take 4, array of 2 short take 4 (2x2) and array of 3 byte takes 3 byte.

Smallest allocatable in memory is byte!
(hurray! less painful bitshift for me!)

1 Like

@jflecool2, one word of caution here :wink:

As I’ve been looking into this a bit more in this thread the answer is not that straight forward - unfortunately :frowning:

In short: You cannot only look at the variables isolated to answer your question, but you have to pay attention to the order how you place your variabls in relation to eachother.
psb777 has been (un)lucky with his test there since he had two chars followed by two ints which turned out as (1 + 1 + 2 + 2 = 6) but if he had one char followed by one long it would not have been (1 + 4 = 5) but (1 (+3) + 4 = 8) because the long needs to start at a four byte boundary.
Knowing this you could make specific use of these extra bytes by reordering your variables to fall into otherwise open gaps.

1 Like

That's pretty deep. Is there a utility that might be able to ingest some sample code and suggest variable declaration orders? If I understood it better, I'd try to create that utility myself!

AFAIK there are at least two GCC in-built ways to achieve this.
The one is #pragma pack( push,n | pop ) and the second __attribute__((packed[, aligned(n)])) that instruct the compiler to overrule the standard alingnment (e.g. stuffing) to some other boundary n (where n has to be a power of 2).

Doing so might help to save space but might result in slower code execution or even lead to crashes when used on variables that must be dword aligned (e.g. pointers - I guess).

So I’d think it would be a hard task to build a tool doing this for you completely automatic.
But being aware of the fact helps you to use one of the above when appropriate.