7

I would like to debug my code and can't access the internal layer in the process since this would disturb the communication with the hardware. (volatile operations are performed where the watchlist would interfere with the basic read accesses.)

So I'm testing the interface's return values but the IAR compiler does even optimize unused volatile variables away.

and a statement like this:

i = object.foo();
if (i)i=i;

doesn't help either.

I found here on SO just answers that advice for that case to use i/o operations. but that's no option either, since I don't have the option of including the C standard libraries. and the project itself doesn't need i/o there is no own variant of input/output functions.

So what are my options except disabling the optimizer?

Clifford
  • 88,407
  • 13
  • 85
  • 165
dhein
  • 6,431
  • 4
  • 42
  • 74
  • What do you mean with "unused volatile variables away"? – too honest for this site Sep 16 '15 at 12:42
  • When debugging, the proper solution is actually to disable the optimizer. Avoid debugging optimized code unless you are a masochist. – Lundin Sep 16 '15 at 12:53
  • @Olaf: Don't understand your question? that they get trimmed anyway. I thought volatile would prevent this but I missunderstood the scheme. – dhein Sep 16 '15 at 14:26
  • @Lundin your probably right with that, and my conclusion is that that would be indeed the cleanest and most efective way. you should add that to your answer as it even increases your posts quality ;) – dhein Sep 16 '15 at 14:27
  • It's legal to optimize out unused `volatile` variables. _Writing_ and _reading_ them is observable behavior and may not be optimized out, but then they're obviously no longer unused. – MSalters Sep 16 '15 at 14:30
  • You specifically asked how to do it without disabling the optimizer. – Lundin Sep 16 '15 at 14:30
  • @MSalters: I'm not saying thats wrong. I was just not aware of when I posted the code. – dhein Sep 16 '15 at 14:31
  • @Lundin: true story, but anyway I would thing it should be noted after my personal impression growth i walked thorugh the last 2 hours. But what ever you do. your answer is satisfing. – dhein Sep 16 '15 at 14:35
  • @Zaibis: It is not clear to me. You do not read nor write the variables, nor are they hardware-registers (I presume the latter), so why is it a problem anyway they get optimized-out? The only point left would be DMA buffers, but even these would have to be allocated and accessible from your code (at least to write their address to the DMA). – too honest for this site Sep 16 '15 at 16:22
  • Have you tried `#pragma required=symbol`? It should not work with local variables, but should keep any statically linked variable or function. – user694733 Sep 17 '15 at 08:16
  • @Olaf the point is, because I'm debugging. and in case I'm debugging It would be nice to have the variable exist when I'm watching it. – dhein Sep 17 '15 at 08:38
  • @Olaf: And if you are arguing I could simply watch the variables where the calculations come from, thant thats what I tryed to describe in the OP: I can't watch them, because they are configured to be overwritten by next value after beeing read. and the IAR watchlist it self woudl be triggering the "registry was read" event, so the programm flow which in generall is ensured would become desynced and the programm wouldn't work probably anymore. so I need to check them some where else. and as thats not so easy my approach was, its best just declarign some variables for debug purposes. – dhein Sep 17 '15 at 08:43
  • @Zaibis: Hmm.. I did something similar with gcc and had no problems. However, it is often necessary anyway to do destructive debugging: set watch/breakpoints wisely, run and once triggered inspect the state, then reset and start over. Some modern MCUs (e.g. STM32) allow to stop certain clocks if the CPU is halted, btw. An alternative is to use trace features (some allow to include a custom data stream, including timestamps) or the classical serial link (which might as well be SPI). – too honest for this site Sep 17 '15 at 09:38

2 Answers2

5

A common way is to put it into a while loop via a macro.

#define KEEP_UNUSED(var) do { (void)var; } while(false);

IAR also has an extension called __root: http://supp.iar.com/FilesPublic/UPDINFO/004350/manuals.htm

The __root attribute can be used on either a function or a variable to ensure that, when the module containing the function or variable is linked, the function or variable is also included, whether or not it is referenced by the rest of the program.

HelloWorld
  • 2,392
  • 3
  • 31
  • 68
  • I was thinking of a loop aswell but that looked to me like an awfull work. but the macro idea didn't came into my mind. should be doing it. I'll let you know. – dhein Sep 16 '15 at 11:54
  • the gcc edit I was aware of, but I'm using IAR's commercial compiler for embedded systems. (which one might assume should be aware of such cases and at least respect volatiles for that reason...) – dhein Sep 16 '15 at 11:56
  • By the way, I assume you meant var isntead of expr, don't you? – dhein Sep 16 '15 at 11:59
  • And nope, even after beeing used in a false loop the compiler is able to cross it out. So sadly this isn't solving my problem. – dhein Sep 16 '15 at 12:00
  • I fixed the expr thing. And I missed you use IAR. IAR has a special extension called **__root**. See http://supp.iar.com/FilesPublic/UPDINFO/004350/manuals.htm Does that work? – HelloWorld Sep 16 '15 at 12:02
  • definitely the right answer! gcc will keep optimise out unused vars no matter what I tried – yo3hcv Jun 16 '22 at 14:50
5

The most reliable way is to find a setting in your linker files that forces a certain variable to get linked. But that's of course completely system-dependent.

Otherwise, the portable standard solution is simply to write (void)i; somewhere in the code. That works for most compilers. If it doesn't, you can take it one step further:

#ifdef DEBUG_BUILD
volatile int dummy;

// all variables you would like to have linked:
dummy = i; 
dummy = j;
...
#endif

Or if you are fond of obscure macros:

#define FORCE_LINKING(x) { void* volatile dummy = &x; }

(void* since that is type generic and works for every kind of variable. * volatile to make the pointer itself volatile, meaning the compiler is forbidden to optimize away the write to it.)

Lundin
  • 195,001
  • 40
  • 254
  • 396