Keith Thompson said:
And, of course, unions and classes are two different things. The
point of a union is that the members are all stored in the same
location (and reading a member other than the last one written invokes
undefined behavior in most cases).
Regarding unions and their usefulness, can anyone point out UB in the
following code? It tries to stack up "local" variables in an array of
char intended to be used by a call hierarchy of statemachines. To save
memory, only the actually needed local variables are allocated,
although the enclosing union is larger. How bad is this with regard to
the standard?
#include <stdio.h>
#include <stdint.h>
enum fsm_state { IDLE, LOAD, STORE, SEARCH };
struct fsm_common{ enum fsm_state State; };
struct fsm_type1{ enum fsm_state State; int Length; long Addr; };
struct fsm_type2{ enum fsm_state State; long Start; long Stop; long
Addr; };
union fsm_locals{ struct fsm_common common; struct fsm_type1 type1;
struct fsm_type2 type2; };
union fsm_locals* align_to_union(char *ptr) // non-portable
{
uintptr_t a = (void*)ptr; // architecture & implementation dep.
return (void*)((a+3u)&~3u); // choose any alignment appropriate for
the union
}
void* alloc_on_stack(char **StackPtr,size_t s)
{
union fsm_locals* r = align_to_union(*StackPtr);
*StackPtr = (char*)r+s;
return (void*)r;
}
void init_fsm(char *StackPtr)
{
union fsm_locals *locals = align_to_union(StackPtr);
locals->common.State = IDLE;
}
void bar(char *StackPtr)
{
struct fsm_type2 *locals = alloc_on_stack(&StackPtr,sizeof
*locals);
switch(locals->State)
{
case IDLE: locals->State = SEARCH;
break;
case SEARCH: locals->Start = locals->Addr = 0xcccccccc;
locals->Stop = 0xdddddddd;
break;
}
}
void foo(char *StackPtr)
{
struct fsm_type1 *locals = alloc_on_stack(&StackPtr,sizeof
*locals);
switch(locals->State)
{
case IDLE: locals->Length = 0xaaaaaaaa;
locals->Addr = 0xbbbbbbbb;
init_fsm(StackPtr);
locals->State = LOAD;
break;
case LOAD: bar(StackPtr);
break;
}
}
int main(void)
{
unsigned char Stack[2*sizeof(union fsm_locals)];
int i;
init_fsm(Stack);
foo(Stack); foo(Stack); foo(Stack);
for(i=0;i<2*sizeof(union fsm_locals);i++) printf("%.2x " ,
Stack
);
return 0;
}
regards,
Mark