tags:

views:

99

answers:

5

Is it a good practice to group all the variables of same type together while declaring in local scope within a function? If yes, why? Does it solve memory alignment issues?

+3  A: 

It depends on the compiler; i.e. the compiler will layout memory as it sees fit. So other than being good style, it has no effect (at least in any modern compilers I've used).

Mitch Wheat
+1  A: 

It will not solve alignment issues, since there shouldn't be alignment issues - the compiler will lay out your local variables correctly aligned, so there should be no alignment issues.

The only issue that grouping like-aligned types might have is to reduce use of the stack, but compilers are free to reorder the layout of variables on the stack anyway (or even reuse locations for different local variables at different times, or to keep locals in registers and not ever have them on the stack), so you're generally not buying anything for an optimized compile.

If you're going to be 'type punning' items on the stack, you'll need to use the same methods for alignment safety that you'd use for data off the stack - maybe more, since memory allocated by malloc() or new is guaranteed to be appropriately aligned for any type - that guarantee is not made for storage allocated to automatic variables.

'Type punning' is when you circumvent the type system. such as by accessing the bytes in a char array as an int by casting a char* to an int*:

int x;
char data[4];

fill_data( data, sizeof(data));

int x = *(int*) data;

Since the alignment requirement of the char[] might be different from an int, the above access of data through an int* might not be 'alignment safe'. However, since malloc() is specifed to return pointers suitably aligned for any type, the following should not have any alignment problems:

int x;
char* pData = malloc( 4);

if (!pData) exit(-1);

fill_data( pData, 4);

x = *(int*) pData;

However, note that sizeof(int) might not be 4 and int types might be little- or big-endian, so there are still portability issues with the above code - just not alignment issues. There are other ways of performing type punning including accessing data through different members of a union, but those may have their own portability issues notably that accessing a member that wasn't the last written member is unspecified behavior.

Michael Burr
Your last paragraph is not clear. Can you elaborote? Thanks!
Jay
@Jay: I've expanded on the last paragraph. Let me know if this still doesn't make things clear.
Michael Burr
+6  A: 

I think it mattered with the VAX C compiler I used 20 years ago, but not with any modern compiler. It is not safe to assume that local variables will be in any particular order, certainly not safe to assume they will be in the order you declared them. I have definitely seen the MSVC compiler reorder them.

Grouping variables of the same type does help when they are fields of a struct, because the ordering of fields of a struct is guaranteed to match the order of declaration.

John Knoeller
@Blindy: you have it backwards from what John's answer says.
unwind
@Blindy: John said the opposite, that the ordering of a struct is guaranteed.
Michael Burr
Sorry my bad, I misread it.
Blindy
+1  A: 

In general it will not help for local variables. There are optimization rules which can be applied by the complier and additional "pragma" directives that could be used to manipulate the alignment.

Alexey Kalmykov
A: 

Padding and alignment issues only matter for structs, not local variables, because the compiler can put local variables in whatever order it wants. As for why it matters in structs -

Many C compilers will align struct members by inserting padding bytes between them. For example, if you have a struct S { int a; char b; int c; char d; int e; }, and the target hardware requires that ints be aligned on 4-byte boundaries, then the compiler will insert three bytes of padding between b and c and between d and e, wasting 6 bytes of memory per instance. On the other hand, if the members were in order a c, e, b, d, then it will insert two bytes of padding at the end (so that the size of S as a whole is a multiple of 4, so the members will be properly aligned when in arrays), wasting only 2 bytes per instance. The rules are very much platform and compiler-specific; some compilers may rearrange members to avoid padding, and some have extensions to control the padding and alignment rules in case you need binary compatibility. In general, you should only care about alignment if you're either reading/writing structs directly and depending on them having the same layout (which is usually a bad idea), or you expect to have lots of instances and memory is at a premium.

jimrandomh