Most compilers will automatically align data values to the word size of the platform, or to the size of the data type, whichever is smaller. The vast majority of consumer and enterprise processors use a 32 bit word size. (Even 64 bit systems usually use 32 bits as a native word size)
As such, the ordering of members in your struct could possibly waste some memory. In your specific case, you're fine. I'll add in comments the actual footprint of used memory:
typedef struct structc_tag{ char c; // 1 byte // 3 bytes (padding) double d; // 8 bytes int s; // 4 bytes } structc_t; // total: 16 bytes
This rule applies to structures too, so even if you rearranged them so the smallest field was last, you would still have a struct of the same size (16 bytes).
typedef struct structc_tag{ double d; // 8 bytes int s; // 4 bytes char c; // 1 byte // 3 bytes (padding) } structc_t; // total: 16 bytes
If you were to declare more fields that were smaller than 4 bytes, you could see some memory reductions if you grouped them together by size. For example:
typedef struct structc_tag{ double d1; // 8 bytes double d2; // 8 bytes double d3; // 8 bytes int s1; // 4 bytes int s2; // 4 bytes int s3; // 4 bytes short s4; // 2 bytes short s5; // 2 bytes short s6; // 2 bytes char c1; // 1 byte char c2; // 1 byte char c3; // 1 byte // 3 bytes (padding) } structc_t; // total: 48 bytes
Declaring a stupid struct could waste a lot of memory, unless the compiler reorders your elements (which, in general, it won't, without being explicitly told to)
typedef struct structc_tag{ int s1; // 4 bytes char c1; // 1 byte // 3 bytes (padding) int s2; // 4 bytes char c2; // 1 byte // 3 bytes (padding) int s3; // 4 bytes char c3; // 1 byte // 3 bytes (padding) } structc_t; // total: 24 bytes // (9 bytes wasted, or 38%) // (optimal size: 16 bytes (1 byte wasted))
Doubles are larger than 32 bits, and thus according to the rule in the first section, are 32 bit aligned. Someone mentioned a compiler option that changes the alignment, and that the default compiler option is different between 32 and 64 bit systems, this is also valid. So the real answer about doubles is that it depends on the platform and the compiler.
Memory performance is governed by words: loading from memory happens in stages that depend on the placement of data. If the data covers one word (i.e. is word aligned), only that word need be loaded. If it is not aligned correctly (i.e. an int at 0x2), the processor must load 2 words in order to correctly read its value. The same applies to doubles, which normally take up 2 words, but if misaligned, take up 3. On 64 bit systems where native loading of 64 bit quantities is possible, they behave like 32 bit ints on 32 bit systems in that if properly aligned, they can be fetched with one load, but otherwise, they will require 2.
doublealignemnt is enforced with-malign-double).