Less memory than CASE

Hello.
I am trying to optimize my code space. Is there another way of using CASE that takes up less memory. Eg

void ctrl_Click() {
switch (app_page) {
case 1: // ** Page_SWR
doSwrFreq();
break;
case 2: // ** Page_GEN
set_GEN_cursor_pos();
break;
case 3: // ** Page_GEN
set_GEN_cursor_pos();
break;
}
}

Well, in your case, since case 2 and 3 both do the same thing, you can probably just use a ternary operator considering you only have two outcomes.

Maybe an array of function pointers. Try it and let us know ;)

Please use code tags when posting. The posted code is equivalent to:

void ctrl_Click() {
  switch (app_page) {
    case 1:   // ** Page_SWR
      doSwrFreq();
      break;
    case 2:
    case 3:   // ** Page_GEN
      set_GEN_cursor_pos();
  }
}

but I imagine that the compiler would figure that out.

What should happen if app_page is not 1, 2 or 3?

jremington: What should happen if app_page is not 1, 2 or 3?

Good question, which is why I usually have a default:

void ctrl_Click() {
  switch (app_page) {
    case 1:   // ** Page_SWR
      doSwrFreq();
      break;
    case 2:
    case 3:   // ** Page_GEN
      set_GEN_cursor_pos();
      break;
    default:
       Serial.print("I shouldn't be here. app_page = ");
       Serial.println(app_page);
       break;
  }
}

compiling all code gives me - 28164 bytes (98%) of program storage space. Maximum is 28672 bytes.

Changing the code to:

// Button actions
void ctrl_Click() {
  switch (app_page) {
    case 1:   // ** Page_SWR
      doSwrFreq();
      break;
    case 2:   // ** Page_GEN
    case 3:   // ** Page_GEN
      set_GEN_cursor_pos();
      break;
  }
}

doesn't change size at all. .. but thanks jremington, I didn't realise you could trim case like that.

.. don't need a default, its always going to be 1, 2 or 3.

"compiling all code gives me - 28164 bytes (98%) of program storage space. Maximum is 28672 bytes."

What you posted isn't nearly that big. If you want help reducing memory footprint then post the whole thing. That switch case is about as small as you can make it.

No point posting all code - I am now working on the CASE (SWITCH) statements now. There's quite a few directing program flow. So i picked the smallest to make the topic as light weight as possible. Logic being if I can trim 1 due to some C technique I'm not aware of, I can apply this to the rest without bloating the forum.

So this c ode does the same thing, is harder to read and compiles to same size:

void ctrl_Click() {
  if (app_page == 1) {
    doSwrFreq();
  } 
  if (app_page > 1) {
    set_GEN_cursor_pos();
  }
}

Does anyone know of a "memory tighter" way of coding this?

The code that you don't show uses far more than the 'few' bytes of your switch/case or if/else. So why bother?

cday-nz: No point posting all code - I am now working on the CASE (SWITCH) statements now. There's quite a few directing program flow. So i picked the smallest to make the topic as light weight as possible. Logic being if I can trim 1 due to some C technique I'm not aware of, I can apply this to the rest without bloating the forum.

That's a misguided effort. For one thing, most serious coders would rather read something clear and self-expressive than something opaque and cleverly efficient. Also, if you have a surplus of case statements, it is a "red flag" that your program design needs code factoring and restructuring.

It's an odd statement because you seemed to be talking about compiled code efficiency before.

+1 to the above two comments. This is a waste of time and effort.

I’ll bet that in the unposted code, there are many other ways to significantly reduce the total program size.

The project consists some 15x C files and other standard Arduino libraries. These include the already heavily optimized PDQ libs for ST7735, I2C & GFX by Xark. Other libs are older si5351 from Jason Milldrum & Dana H. Myers. Most of the code in these libs are class's and I've worked out that they take no space until called.

Where I am now at is as described - case / switch statements. From the responses so far, seems there is not a glaringly obvious optimization method in what I am doing. If there was, I'm sure it would have been pointed out.

I am really very appreciative of all comments, feedback and time.

I've worked out that they take no space until called.

How do you imagine that works? The hex file that is uploaded into the Arduino's program space is all you get, so all the code that runs has to be in it.

Trimming libs that have code for boards.chips you aren't using would get you more than fiddling with switch case.

As for " I've worked out that they take no space until called." PLEASE show how you worked that out. I would love to know.

INTP: Trimming libs that have code for boards.chips you aren't using would get you more than fiddling with switch case.

Normally the compiler will just ignore such code and there will be no memory penalty.

OK, sorry, I forgot I was talking to programmers.

So take PDQ_GFX.h

The class PDQ_GFX has DrawRoundedRec in the public definitions.

What I was trying to say was that in my program, if I do not call / use DrawRoundedRec, then it will not be compiled into the hex.

To prove this I commented out everything to do with DrawRoundedRec (an every other defined function / procedure that was declared and that I wasn't using) - there was no difference in hex size.

Im probably using the wrong terminology to explain what I mean - sorry, i'm an old Dataflex programmer...

Yes, however I would like to add that you should have a good reason for including libraries you don't use. Else it just creates confusion and clutter. Do what you say, say what you do.

Anyway, it has no bearing on your efficiency. You haven't really saved any memory because you didn't need that stuff in the first place.

Hmm… I am actually using all libraries i have included. But not all parts of all libraries. Consider this code:

template <class HW>
class PDQ_GFX : public Print {

  public:
    PDQ_GFX(coord_t w, coord_t h);	// Constructor (called by HW driver)

    // Graphic primitives
    // drawPixel MUST be defined by the driver subclass (and has no generic fall-back):

    // These are generic versions of routines for drivers that don't provide device-optimized code.
    // Drivers are required to have these functions (without "_" postfix), but can fall back to using
    // these if needed (they should not be called directly with "_" postfix or it will bypass any
    // device-optimized implementations).
    static void drawLine_(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
    static void drawFastVLine_(coord_t x, coord_t y, coord_t h, color_t color);
    static void drawFastHLine_(coord_t x, coord_t y, coord_t w, color_t color);
    static void fillRect_(coord_t x, coord_t y, coord_t w, coord_t h, color_t color);
    static void fillScreen_(color_t color);

    // These are usually overridden in the driver subclass to be useful (but not internally referenced)
    static void setRotation(uint8_t r);	// only swaps width/height if not supported by driver
    static void invertDisplay(boolean i);	// only if supported by driver

    // These exist in PDQ_GFX (and generally have no subclass override)
    static void drawRect(coord_t x, coord_t y, coord_t w, coord_t h, color_t color);
    static void drawCircle(coord_t x0, coord_t y0, coord_t r, color_t color);
    static void drawCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, color_t color);

… thats only a fraction of part of one library so I hopefully can get my meaning across.

I’m not using setRotation( or drawCircle( - but they are still there. It make no difference to hex size, program size if they are commented out or not - as long as i am not using them.

Well, yes, you don’t have to comment out parts of a library that you don’t use. What is the point you are making? You are not getting your meaning across. The only way to save memory when using a library would be to find a way to avoid using some functions, but you haven’t said anything like that.

What I have managed to do to save some space (from 28,164 down to 28,142) is understand that I do not need to repeat CASE statements eg this

  case 2:   // ** Page_GEN
      set_GEN_cursor_pos();
      break;
    case 3:   // ** Page_GEN
      set_GEN_cursor_pos();
      break;

actually works the same as this

    case 2:   // ** Page_GEN
    case 3:   // ** Page_GEN
      set_GEN_cursor_pos();
      break;

But, it didn't show any compiler savings until i have trimmed 3 different cases, all in a similar repetitive nature to this...