Skip to main content

IAR Embedded Workbench for Arm 9.70.x

Introduction to working with variables and expressions

In this section:

This page introduces different methods for looking at variables and introduces some related concepts.

Briefly about working with variables and expressions

There are several methods for looking at variables and calculating their values. These methods are suitable for basic debugging:

  • Tooltip watch—in the editor window—provides the simplest way of viewing the value of a variable or more complex expressions. Just point at the variable with the mouse pointer. The value is displayed next to the variable.

  • The Auto window displays a useful selection of variables and expressions in, or near, the current statement. The window is automatically updated when execution stops.

  • The Locals window displays the local variables, that is, auto variables and function parameters for the active function. The window is automatically updated when execution stops.

  • The Watch window allows you to monitor the values of C-SPY expressions and variables. The window is automatically updated when execution stops.

  • The Live Watch window repeatedly samples and displays the values of expressions while your application is executing. Variables in the expressions must be statically located, such as global variables.

  • The Statics window displays the values of variables with static storage duration. The window is automatically updated when execution stops.

  • The Macro Quicklaunch window and the Quick Watch window give you precise control over when to evaluate an expression.

  • The Symbols window displays all symbols with a static location, that is, C/C++ functions, assembler labels, and variables with static storage duration, including symbols from the runtime library.

These additional methods for looking at variables are suitable for more advanced analysis:

  • The Data Log window and the Data Log Summary window display logs of accesses to up to four different memory locations you choose by setting data log breakpoints. Data logging can help you locate frequently accessed data. You can then consider whether you should place that data in more efficient memory.

  • The Event Log window and the Event Log Summary window display event logs produced when the execution passes specific positions in your application code. The Timeline window graphically displays these event logs correlated to a common time-axis. Event logging can help you to analyze program flow and inspect data correlated to a certain position in your application code.

    The Cortex ITM communication channels are used for passing events from a running application to the C-SPY Event log system. There are predefined preprocessor macros that you can use in your application source code. An Event log will be generated every time such macros are passed during program execution. You can pass a value with each event. Typically, this value can be either an identifier or the content of a variable or a register (for example, the stack pointer). The value can be written in 8, 16, or 32-bit format. Using a smaller size will reduce the bandwidth needed on the SWO wire. Events can be generated with or without an associated PC (program counter) value, the PC value makes it possible for the debugger to correlate the event to the executed code.

For more information about these windows, see The application timeline.

C-SPY expressions

C-SPY expressions can include any type of C expression, except for calls to functions. The following types of symbols can be used in expressions:

Expressions that are built with these types of symbols are called C-SPY expressions and there are several methods for monitoring these in C-SPY. Examples of valid C-SPY expressions are:

i + j
i = 42
myVar = cVar
cVar = myVar + 2
#asm_label
#R2
#PC32
my_macro_func(19)

If you have a static variable with the same name declared in several different functions, use the notation function::variable to specify which variable to monitor. For global variables (variables defined in file scope), you can use the notation module\variable—the same syntax that is used to denote variables in the Statics window. For example, if there are two source files source_a.c and source_b.c, each with an identical static int var = 0; definition, you can write source_a\var or source_b\var to specify a specific variable.

Note

On 64-bit architectures, the expression #PC becomes ambiguous in C-SPY macros. Therefore, when you debug a 64-bit MCU, you must use #PC32 for AArch32 and #PC64 for AArch64 in C-SPY macros. When debugging a 32-bit MCU, use #PC.

C/C++ symbols

C symbols are symbols that you have defined in the C source code of your application, for instance variables, constants, and functions (functions can be used as symbols but cannot be executed). C symbols can be referenced by their names. Note that C++ symbols might implicitly contain function calls which are not allowed in C-SPY symbols and expressions.

Note

Some attributes available in C/C++, like volatile, are not fully supported by C-SPY. For example, this line will not be accepted by C-SPY:

sizeof(unsigned char volatile __memattr *)

However, this line will be accepted:

sizeof(unsigned char __memattr *)

Assembler symbols

Assembler symbols can be assembler labels or registers, for example the program counter, the stack pointer, or other CPU registers. If a device description file is used, all memory-mapped

peripheral units, such as I/O ports, can also be used as assembler symbols in the same way as the CPU registers. See Modifying a device description file.

Assembler symbols can be used in C-SPY expressions if they are prefixed by #.

Example

What it does

#PC32++

Increments the value of the program counter.

myVar = #SP

Assigns the current value of the stack pointer register to your C-SPY variable.

myVar = #label

Sets myVar to the value of an integer at the address of label.

myptr = &#label7

Sets myptr to an int * pointer pointing at label7.

Table 18. C-SPY assembler symbols expressions 


In case of a name conflict between a hardware register and an assembler label, hardware registers have a higher precedence. To refer to an assembler label in such a case, you must enclose the label in back quotes ` (ASCII character 0x60). For example:

Example

What it does

#PC32

Refers to the program counter.

#´PC32´

Refers to the assembler label PC32.

Table 19. Handling name conflicts between hardware registers and assembler labels 


Which processor-specific symbols are available by default can be seen in the Registers window, using the CPU Registers register group. See Registers window.

C-SPY macro functions

Macro functions consist of C-SPY macro variable definitions and macro statements which are executed when the macro is called.

For information about C-SPY macro functions and how to use them, see Briefly about the macro language.

C-SPY macro variables

Macro variables are defined and allocated outside your application, and can be used in a C-SPY expression. In case of a name conflict between a C symbol and a C-SPY macro variable, the C-SPY macro variable will have a higher precedence than the C variable. Assignments to a macro variable assign both its value and type.

For information about C-SPY macro variables and how to use them, see Reference information on the macro language.

Using sizeof

According to standard C, there are two syntactical forms of sizeof:

sizeof(type)
sizeof expr

The former is for types and the latter for expressions.

Note

In C-SPY, do not use parentheses around an expression when you use the sizeof operator. For example, use sizeof x+2 instead of sizeof (x+2).

Limitations on variable information

The value of a C variable is valid only on step points, that is, the first instruction of a statement and on function calls. This is indicated in the editor window with a bright green highlight color. In practice, the value of the variable is accessible and correct more often than that.

When the program counter is inside a statement, but not at a step point, the statement or part of the statement is highlighted with a pale variant of the ordinary highlight color.

Effects of optimizations

The compiler is free to optimize the application software as much as possible, as long as the expected behavior remains. The optimization can affect the code so that debugging might be more difficult because it will be less clear how the generated code relates to the source code. Typically, using a high optimization level can affect the code in a way that will not allow you to view a value of a variable as expected.

Consider this example:

myFunction()
{
 int i = 42;
 ...
 x = computer(i); /* Here, the value of i is known to C-SPY */
 ...
}

From the point where the variable i is declared until it is actually used, the compiler does not need to waste stack or register space on it. The compiler can optimize the code, which means that C-SPY will not be able to display the value until it is actually used. If you try to view the value of a variable that is temporarily unavailable, C-SPY will display the text:

Unavailable

If you need full information about values of variables during your debugging session, you should use the lowest optimization level during compilation, that is, None.