Large switch statement gives: "relocation truncated to fit:"

I have code with a large switch statement. All the code blocks are small but there are many of them:

switch(a) {
case 0: doSomething(); break;
case 1: doSomethingElse(); break;
...
case 20: doSomethingBetter(); break;
default: doSomethingUnknown();
}

When I added an extra case statement I got this compiler error:
relocation truncated to fit: R_AVR_7_PCREL against `no symbol'

Googling that it seems to do with the generated assembler not being able to create a jump statement. At least this problem gets caught at compile time. But it's starting to make me a little nervous - I come from a high level programming background (app development for Windows), and now this (along with another post about stack issues) is making me remember that I'm programming on a __micro__controller. But with a high level set of libraries and a "high level mindset".

Any words of wisdom as to how to find out more about these sorts of limits? I want to keep using the Arduino libraries and I want to continue to write "high level" code (for all the usual productivity reasons). If I knew more about the limits then I could (maybe!) design and code appropriately.

Any insight or advice greatly received!

Thanks.

Any words of wisdom as to how to find out more about these sorts of limits?

Run into them the hard way!
Pay attention where it says "Binary Sketch Size"!
Think "sizeof" for each and every global, static, string literal, and local variable you use!
Never, ever, use heap-based allocation (new/delete/malloc/free). Pre-allocate everything you need as globals. Then you know it's there!
Use objdump to examine the generated elf file (hold shift and press the play button to see where the environment puts your generated files).

It is possible that you can turn your switch into a table of function pointers.

void (*table)[21] = {
 &func0,
 &func1,
 ...
};

void doit(int n) {
  if (n < 0 || n > 20) {
    funcDefault();
  }
  else {
    (*table[n])();
  }
}

If everything's a global anyway, you don't need to pass local variables along.

Really, when you have 2 kB of global data segment and stack space COMBINED, you just can't create enough globals that you can't find all references when you need them :slight_smile:

Thanks!

Run into them the hard way!

Yup - that's what I'm doing now. Not very efficient though.

Pay attention where it says "Binary Sketch Size"!

That just tells me how much Flash memory I've used, right? Not really much help in this case. Unless I'm missing something? (BTW, I'm at 40K out of 128K).

Think "sizeof" for each and every global, static, string literal, and local variable you use!

But if I don't know my running limits that doesn't really help that much. Unless I keep a running total in my head - but that's why I've got a compiler!

Never, ever, use heap-based allocation (new/delete/malloc/free). Pre-allocate everything you need as globals. Then you know it's there!

Ahh, good point. This is one of those low-level vs. high-level type differences. I've years of coding high-level where memory is bountiful and passing parameters is usually considered better form than globals. I totally take your point though - globals are good!

(BTW, I don't have any heap allocation in this app - but I do in another one. Time to go and eradicate that!)

Use objdump to examine the generated elf file (hold shift and press the play button to see where the environment puts your generated files).

Excellent - this is the sort of nugget I was looking for.

It is possible that you can turn your switch into a table of function pointers.

Another good point - you saved the best two for last :wink:
I've been meaning to tidy up that big ass switch statement anyway so making it table driven will make me do some good tidy up.

Really, when you have 2 kB of global data segment and stack space COMBINED, you just can't create enough globals that you can't find all references when you need them :slight_smile:

Right! I must write out "Globals are Good" on the blackboard 100 times! (Hey. maybe that could be a new one for the start of the Simpsons?)

Thanks again.

There are a couple of functions you can find on the forums, freemem, freememory that will tell you how much free space you have between stack & heap. Here's one implementation I found a while back:

// this function will return the number of bytes currently free in RAM      
extern int  __bss_end; 
extern int  *__brkval; 
int freemem()
{ 
 int free_memory; 
 if((int)__brkval == 0) 
   free_memory = ((int)&free_memory) - ((int)&__bss_end); 
 else 
   free_memory = ((int)&free_memory) - ((int)__brkval); 
 return free_memory; 
}