The problem is that case a switch branches expect a constant value. In particular, a constant that is known at compile time. The line address is not known at compile time - the linker knows the address, but not even the last address. I think the final, moved, address is only available at runtime.
You can simplify your problem to
void f() { int x[*(int*)"x"]; }
This gives the same error, since the address of the "x" literal is unknown at compile time. This is different from, for example,
void f() { int x[sizeof("x")]; }
Since the compiler knows the size of the pointer (4 bytes in 32-bit strings).
Now, how to fix your problem? Two things come to mind:
Do not add a string, but an integer to the id field, and then use the list of constants in your case .
I suspect that you will need to make a switch like this in several places, so my other suggestion is: do not use switch to execute code primarily depending on the type of structure. Instead, the structure may offer a pointer to a function that can be called to make the correct printf call. When creating the structure, the function pointer is set to the correct function.
Here's a code snippet illustrating the second idea:
struct MyStructure { const char *id; void (*printType)(struct MyStructure *, void); void (*doThat)(struct MyStructure *, int arg, int arg); }; static void printSqrtType( struct MyStructure * ) { printf( "its a sqrt\n" ); } static void printLog2Type( struct MyStructure * ) { printf( "its a log2\n" ); } static void printLog2Type( struct MyStructure * ) { printf( "works somehow, but unreadable\n" ); } void setupVTable( struct MyStructure *s ) { if ( !strcmp( s->id, "sqrt" ) ) { s->printType = printSqrtType; } else if ( !strcmp( s->id, "log2" ) ) { s->printType = printLog2Type; } else { s->printType = printUnreadableType; } }
With this in place, your source code can simply do:
void f( struct MyStruct *s ) { s->printType( s ); }
This way you centralize type checking in one place, rather than cluttering your code with a multitude of switch .