0

I have just been taught a new knowledge about how to optimize memory .
Concept says: Variable will always be stored in an area of ​​8 bytes, if not 8 bytes it will be filled with padding.
You can see the illustration with the photo.

Memory Alignment

I tried to test it with the sizeof() command, ironically it didn't work as expected. Is that correct? How do I prove it with code?

जलजनक
  • 3,072
  • 2
  • 24
  • 30
Ngoc Anh
  • 21
  • 5
  • 1
    Check memory addresses of variables. – जलजनक Apr 02 '22 at 16:15
  • 1
    `struct foo { int a; _Bool b; char c[11]; double d; }; struct foo f; printf("%p %p %p %p\n", (void*)&f.a, (void*)&f.b, (void*)f.c, (void*)&f.d);` ... mix and match at will – pmg Apr 02 '22 at 16:17
  • 2
    Ngoc Anh, "Variable will always be stored in an area of ​​8 bytes" is not specified by C. Avoid such ideas that are taught as gospel when its an implementation specific concept. – chux - Reinstate Monica Apr 02 '22 at 16:40
  • 2
    Ngoc Anh, "it didn't work as expected." --> better to also post that value than only weakly describe it. Posting code used to report it is a plus. – chux - Reinstate Monica Apr 02 '22 at 16:41
  • 1
    Not always true... Embedded platforms often use byte-aligned data, to avoid wasting the low amount of RAM available. And for transmissions, data are near **always** packed (and endianness is also near always forced), whatever protocol and physical medium is used. Aligning data of machine-word boundaries is a classical "optimization for speed". – Wisblade Apr 02 '22 at 17:02
  • @Wisblade : I suggest "_resource constrained embedded systems_". Not all embedded systems are short of memory. In any event the default alignment will be dependent on the architecture, not the application - the compiler does not generally know it is targeting a resource constrained or embedded system. Where byte alignment/packing is used to conserve memory that would be forced by compiler directive or switch as elected by the developer rather than determined by the compiler. – Clifford Apr 02 '22 at 17:19
  • 1
    @Wisblade : Moreover for architectures where unaligned access is not possible in a single instruction, unaligned member access will generate _more code_, potentially defeating the attempt to somehow save memory. – Clifford Apr 02 '22 at 17:20
  • @Clifford Flash/ROM is not (so) often a problem as RAM. You'll see a lot of microcontrollers with memory sizes like one megabyte Flash, and 16 kilobytes of RAM... More important: this kind of packing isn't usually used on desktop computers, neither on servers (but on things like communication stacks / databases, i.e. "final" destinations for data), but near only within embedded systems. Not all, but on the other side, you'll have difficulties to find that on desktops/servers, while it's frequent in embedded world. Important thing is: OP's "memory optimization" isn't an universal rule. – Wisblade Apr 02 '22 at 17:42
  • @Wisblade : I appreciate all that - I have been developing embedded systems for 32 years. My point is that it is not true that the _default alignment_ will be packed to conserve memory - you have to explicitly request it (though perhaps not on an 8-bit target). Moreover using packing to minimise memory usage is a _bad idea_ - that is not what packing should be used for. In that case the sympathetic ordering of members as suggested here is more appropriate and safer. – Clifford Apr 02 '22 at 17:56
  • @Clifford "Only" 25 years for me... :) Indeed, 8 bits (and often 16 bits too...) targets aren't aligned at all usually. It's a question only for 32-bits and more. But packing can be the default alignment anyway - was the case with Paradigm C++, for example. I didn't said that packing was a _good_ idea, but that this was done for _one_ purpose (saving RAM). It indeed has side-effects that may (or not!) be relevant for a particular project. What I wished to point is that aligning on machine-word is NOT an universal norm for every possible machine. – Wisblade Apr 02 '22 at 20:14

2 Answers2

1

I think you have misunderstood or misstated what you have been taught. The statement:

Variable will always be stored in an area of ​​8 bytes,

is not supported (in fact explicitly contradicted) by your diagram, and if that were true, no amount of "variable arrangement" would have any impact on memory usage because all members would occupy the same space with padding. That is not what the diagram illustrates at all, and I suspect not what you were actually taught.

It is in any event implementation defined, and 8, 16, 32 and 64 bit platforms for example may have differing optimal alignment and a compiler may or may not generate optimal performance alignment if the optimisation goal is minimal space, or compiler directives or options are applied to force different alignment.

For example; what your diagram suggests is that if the bool and the double were swapped, the structure size could be 16 rather than 24 bytes long.

Regarding:

How do I prove it with code?

well since it is implementation defined, you could equally disprove it on some platforms/compiler implementations. However to test the hypothesis, and to investigate any specific implementation, consider:

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>

int main()
{
    struct 
    { 
         bool a ; 
         double b ;  
         uint16_t c ; 
         uint32_t d ; 
    } foo ; 
     
    struct 
    { 
         double b ;  
         bool a ; 
         uint16_t c ; 
         uint32_t d ; 
    } bar ; 
     
    printf("foo: %lu\n", sizeof(foo) ) ;
    printf("bar: %lu\n", sizeof(bar) ) ;

    return 0;
}

At https://onlinegdb.com/jknxFt0Sx at least, it outputs:

foo: 24
bar: 16

Which demonstrates the behaviour suggested in your diagram, but clearly disproves "Variable will always be stored in an area of ​​8 bytes,...".

More importantly the take home here is that generally the ordering of members dependent on their respective sizes can affect the overall size of the structure after implementation defined alignment and padding have been applied.

What the diagram actually illustrates is that members are aligned depending on their size. So single bytes can have any address, 16 bit types have even addresses, 32 bit types have addresses divisible by 4, and 64 bit types by 8. Now that may or may not be true in any particular implementation, but the way to minimise the size of a structure where that is true, is to group members such that they are packed with no padding while maintaining required alignment.

Generally the default alignment can be manipulated (by compiler defined mechanisms). For example in gcc:

    struct 
    { 
         bool a ; 
         double b ;  
         uint16_t c ; 
         uint32_t d ; 
    } __attribute__((packed)) foo ; 
     
    struct 
    { 
         double b ;  
         bool a ; 
         uint16_t c ; 
         uint32_t d ; 
    } __attribute__((packed)) bar ; 

Results in both structures having a size of 15 regardless of the platform's preferred or required alignment. On platforms where unaligned access is not supported, such structures generate additional code to access unaligned members, and may in some (mis)uses cause an exception.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

You confuse size with alignment

A char is always size 1, its defined by the c standard.

Alignment means, is the address of that variable a multiple of some particular value (usually 2, 4, 8 or 16).

Why are variables aligned? On some CPUs various type of data must begin on an even boundaries or even multiples of 4. Other CPU types perform much better with data that is well aligned. Compilers know this and so they will layout things in memory to be correctly and / or optimally aligned.

See

Why is integer assignment on a naturally aligned variable atomic on x86?

INTEL X86,why do align access and non-align access have same performance?

Alignment results in unused memory between variables.

THe sizeof operator tells you the size of the variable regardless of how its aligned. It does not take alignment into account.

pm100
  • 48,078
  • 23
  • 82
  • 145
  • I was going to write a similar answer, and so I have just a suggestion. I had written a small demonstration program to show via resulting addresses that despite different sizes different types are aligned on multiples of equal alignments. Even if that proves nothing but simply shows the effect for the specific architecture used by me. – the busybee Apr 03 '22 at 08:04