-
Notifications
You must be signed in to change notification settings - Fork 15
Article about debugging basics in CLion #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nevemlaci
wants to merge
11
commits into
TCCPP:main
Choose a base branch
from
nevemlaci:clion-debug
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
7669d83
added clion debugging article
nevemlaci 13efc3a
fix missing trailing comma in sidebar
nevemlaci 499430e
fix formatting in the article
nevemlaci 810f774
fix conditional breakpoint code example
nevemlaci 17dbf8f
mark <print> as a C++23 feature
nevemlaci 5b12270
fix code style
nevemlaci a374738
fixed a few uses of the old myFunction name
nevemlaci 9f4b543
prettier :)
nevemlaci b5ed0ba
someOp -> some_op
nevemlaci 38c5611
fix screenshots to contain edited code
nevemlaci bdf6375
fixed warning for evaluating expressions with side effects
nevemlaci File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
# Using the debugger in CLion | ||
|
||
CLion comes with bundled GDB and LLDB, so you don't have to install these yourself. If you are using a toolchain | ||
automatically detected by CLion (see our CLion article), one of these are already selected for you. | ||
|
||
## Placing breakpoints | ||
|
||
Breakpoints are used to stop your program on the given line before the line runs. | ||
|
||
Let's see a small program that defines a variable `x` and multiplies it by 3. We will observe the value of this variable | ||
throughout the program. | ||
|
||
```cpp | ||
int main(){ | ||
int x = 5; | ||
x *= 3; | ||
return 0; | ||
} | ||
``` | ||
|
||
When you hover a line number, a red circle should appear. Click on it to place a breakpoint: Let's place 2 breakpoints, | ||
one on the `x *= 3;` line, and one on the `return 0;` line. | ||
|
||
 | ||
|
||
Let's start our program using the green bug icon. | ||
|
||
## Stepping through your program | ||
|
||
What you'll see as soon as you start your program is that your debugger has hit the first breakpoint and the program is | ||
paused. | ||
|
||
 | ||
|
||
At the bottom of the CLion window, a new "Debug" tab should open. | ||
|
||
The yellow arrow (surrounded by the yellow rectangle) is an indicator of where your program is paused at. | ||
|
||
On the left, you can see the call stack: the functions called in order to reach the line that your program is currently | ||
paused on. We will check this out later. | ||
|
||
To the right, you can see the local variables that are declared in the scope of the function that the program is | ||
currently in. | ||
|
||
In our case, you can see that we only called the `main` function (as well as a bunch of implementation defined C runtime | ||
functions) and our only local variable is `x` with a value of `5`. | ||
|
||
Now we will step through the code line by line. | ||
|
||
We can control the debugger with the "control" buttons at the top of the CLion debug UI. | ||
|
||
The most important ones are: | ||
|
||
 | ||
|
||
- Resume Program: When your program is paused, use this to continue execution (until the program exits or the next | ||
breakpoint is hit). | ||
- Step over: Step to the next line. This will skip any function calls on the current line. | ||
- Step into: Similar to "Step over", but it will step into functions on the current line. | ||
- Step out: Immediately steps out of the current function by running all lines until the function returns.<br> Useful | ||
when you are stuck in some function that you do not care about. | ||
|
||
Click the "Step over" option. Your code will hit the second breakpoint, as it is on the next line (the debugger usually | ||
ignores empty lines). | ||
|
||
As you can see, the previous line that multiplied `x` by 3 executed, so the value of `x` is now 15. | ||
|
||
Now press "Resume Program" to execute the rest of the program | ||
|
||
## Conditional breakpoints | ||
|
||
There are scenarios where you know that your program has a bug when a certain variable has a certain value, but the | ||
value only occurs once every thousand calls or so. This is where conditional breakpoints come in: | ||
|
||
```cpp | ||
int foo(int x) { | ||
return 5 / (x - 3); | ||
} | ||
|
||
int main(){ | ||
[[maybe_unused]] int a = foo(3); | ||
[[maybe_unused]] int b = foo(5); | ||
return 0; | ||
} | ||
``` | ||
|
||
Let's place a breakpoint on the return line of `foo`. Of course the "buggy" value is x=3 in our case (because in that | ||
case we divide by 0), so let's set up a conditional breakpoint for that. Instead of left-clicking on the line number, | ||
right click it. This will bring up a menu where you should select the _Conditional breakpoint..._ option. | ||
|
||
This will bring up a little window where you can enter your condition (`x == 3`). The condition has to be a valid C++ | ||
expression. | ||
|
||
 | ||
|
||
When debugging the program, the breakpoint will be hit on the first function call (as the condition is satisfied), but | ||
not on the second function call. | ||
|
||
## The call stack | ||
|
||
Sometimes you want to know where a function was called from. The call stack shows you all the functions that were called | ||
to reach the current line. | ||
|
||
Let's use this example code: | ||
|
||
```cpp | ||
#include <print> // C++23 feature | ||
|
||
void my_function() { | ||
std::println("print"); | ||
} | ||
|
||
void foo() { | ||
my_function(); | ||
} | ||
|
||
void bar() { | ||
int x = 4; | ||
my_function(); | ||
} | ||
|
||
int main(){ | ||
foo(); | ||
bar(); | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
Now place a breakpoint into the single line of `my_function`. | ||
|
||
Now debug your program. The first time we hit a breakpoint, lets observe the call stack on the UI. | ||
|
||
 | ||
|
||
As you can see, the call stack shows that we first called `foo` from `main`, then called `my_function` from foo. | ||
|
||
Let's resume the program. You should see the second breakpoint being hit. | ||
|
||
 | ||
|
||
We can observe a similar situation as last time, but now `my_function` is being called from `bar`, but this isn't why we | ||
have two functions. Click on the `bar` function on the call stack UI. | ||
|
||
 | ||
|
||
As you can see, you are now observing the state of the locals in the function `bar` right before it called | ||
`my_function`. This is useful to see what context a function was called from. | ||
|
||
Let's resume the program to let it run and quit. | ||
|
||
## Evaluating expressions | ||
|
||
In CLion's debugger, you can evaluate expressions at runtime with the values at the current line. | ||
|
||
Let's see an example. Put a breakpoint on the single line in `my_function`! | ||
|
||
```cpp | ||
#include <print> // C++23 feature | ||
|
||
struct foo { | ||
int x; | ||
int some_op() { | ||
return x * 5; | ||
} | ||
}; | ||
|
||
int my_function(foo f) { | ||
return f.some_op() * 2; | ||
} | ||
|
||
int main(){ | ||
foo f{3}; | ||
int value = my_function(f); | ||
std::print("{}", value); | ||
return 0; | ||
} | ||
``` | ||
|
||
Here, we can't observe the return value of `f.some_op()`, because it isn't a local variable, it is a member function | ||
that has to be ran to be evaluated. Here, we can use the "Evaluate expression" box at the top of the local variable | ||
column. | ||
|
||
 | ||
|
||
As you can see, the expression evaluates to 15, as it should. | ||
|
||
::: warning | ||
|
||
The code you evaluate actually runs and side effects can act weirdly when using this feature. Only use this to test | ||
calculations with no side effects or state changes! | ||
|
||
::: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.