In my code, sometimes when multiple function calls can be made in a single line. I do not get which function is running right now.
for example-
int foo(){
if(m==0||n==0) return 0;
return std::max(foo(a,b,m-1,n),foo(a,b,m,n-1));
}
While debugging, understanding which function was called based on all parameters becomes clumsy and sometimes doesn't even work. Is there any option to see processes within a line while debugging. I use codelite IDE.
When you are having difficulty debugging code, it usually means you are doing too much in a single line. This means you should split a complex statement into multiple statements. In your case, something like this:
int foo(){
if(m==0||n==0) return 0;
auto a = foo(a,b,m-1,n);
auto b = foo(a,b,m,n-1);
return std::max(a, b);
}
Alternatives to the current answer could be:
Stepping into statements. Not likely to work if foo calls are inlined
Debugging disassembly
These alternatives may not work, but if when they work, they allow debugging unaltered code.
Related
I was shown a sample program to demonstrate recursion which looks like it should not work but does. The logic is pretty clear but why does it work even when the recursed function call is not returned? It seems like the return command breaks out of the stack even if it isn't requested to. Is this a language standard or a gcc thing? I saw it with C and C++ compiled with gcc on Windows and Linux.
#include <iostream>
#include <cstdlib>
using namespace std;
int isprime(int num, int i)
{
if (i == 1) {
return 1;
}
else {
if (num % i == 0)
return 0;
else
isprime(num, i-1); // should be returned
}
}
int main(int argc, char** argv)
{
int input = atoi(argv[1]);
cout << input << "\t" << isprime(input, input/2) << "\n";
}
Things like that only work if accidentally the return value happens to be in the register where the caller expects it. This only works if this is realized by your compiler as a recursive function. Technically it is undefined behavior to use the return value of a function that doesn't provide one.
Edit: On modern architectures the return value of a function for values for which it is possible is passed in a specific hardware register. When you call your function recursively, on the bottom in all cases that hardware register is set to the expect value. If by chance when popping up from recursion that hardware register is never changed, you end up with the correct value.
All of this pattern wouldn't work, if the return value would be placed at some location of the stacks of the (recursive) callers.
In any case, all of that should be captured by any modern compiler and give you a warning. If it doesn't you don't have a good compiler, or you are using too defensive command line options.
New year's eve special: In the real world, code like this (with the return) wouldn't even be realized as a recursive function. With not too much effort you will find an iterative variant of that function, and any modern decent compiler should be able to find it as well if you ask for maximal optimization.
A lot here depends what you mean by "it works"?
to try and answer the main point of your question, functions will return when the end of the function is reached, whether or not a return statement is met.
I would expect to see compiler warnings telling you the possible controls paths may not return a value, in C++ at any rate. Resulting in undefined behaviour, see this question:
not returning a value from a non-void returning function
I would say that this example "works" as after a prime is found and isPrime has returned, then the next function up the stack is also free to return. Nothing depends on the return value of isPrime either, so the program will run back up the stack and output something.
...but as behaviour is undefined, the value that actually gets output is likely to be junk. If you are seeing 0 & 1 consistent with primes as input, then wow.
If you think this is working, I would look at testing more broadly with different values.
Also have you been building with any "debug" settings? if so try this again with debug settings off, as thiese sometimes do extra work to keep things uninitialised memory clean.
I can explain exactly what happens:
The function is called, and it recurses back into itself until it reaches the return at either modulo (return 0) or end of recursion (return 1). At this point the function reuturns to the caller, which is is_prime. But there is no more code in the function to execute, so it immediately returns without any further action.
However, you could easily break this by, for example, add printf("Done for %d, %d\n", num, i); behind the call of is_prime() [doesn't have to be in the if-statement]. Or adding a C++ object that is created and destroyed on entry/exit of the function, as another example.
You're just being lucky that it works. And it's very fragile and easy to break - compile it with a different compiler (or with different optimization settings, or a new version of the compiler, or a million other things), and it may well break.
Aren't you forgetting a return statement? For normal recursion you need to put a return before isprime(num,i-1); as well.
I guess this even should give a compile warning if you compile this using strict rules, because the function must always return an int, now it does not (at least if your compiler does not fix this).
Is there a way in Visual Studio to debug a function which is only one line?
Something like:
int foo(int a) { return a + 1; }
It seems when VS enters the function, none of the data has been properly initialized, and upon inspecting the variable 'a', I get garbage data. The data is usually initialized once I step to the next line, but since this is a one line function it never seems to do that, which is quite annoying (as I will need to recompile everything just to inspect the value of a).
If it is simple function, you could start debugging and press Alt+8 for assembly code debug
I don't know if you can step instruction-wise instead of linewise but why don't you just reformat it as
int foo(int a)
{
return a + 1;
}
If I want to stop in an empty block of code it's always a problem.
if (...)
{ // I want the debugger to stop here!
}
If I add an arbitrary line of code which does not affect program behaviour it is likely to be optimized out, depending on the line
if (...)
{
int a;
a = a; // won't work
}
if (...)
{
int a;
int b = a; // will work
}
So the 2 questions arise here:
1) What is the simplest one-line code which will NOT be optimized out (but will really do nothing!), which I can use to stop the debugger?
2) Is there a way to switch all of optimizations so that to be able to stop at an arbitrary line of code? Compiler flag -O0 doesn't work.
A good enough one-line code could be some useful and interesting assert statement with a condition which would not be constant-folded by the compiler. Often some meaningful and useful assert (p!=NULL) orassert(i>0) where p is some existing pointer variable or formal, or i is some existing signed integer variable or formal, is enough.
BTW, you are in the debugging phase of your project, so adding good enough meaningful assert statements is helpful. Of course you want the <cassert> header to be included.
Don't forget that assert(3) statements are skipped if you compile with the -DNDEBUG flag.
You could also use (on Linux/x86) asm volatile ("nop"). Notice that the debugger needs some code to put a breakpoint at. You don't want an empty code.
What about using a static breakpoint?
#include <sys/sdt.h>
if (condition)
DTRACE_PROBE(myapp, foo);
Now you can set a breakpoint in GDB:
break -probe-stap myapp:foo
You can even use:
DTRACE_PROBE1(myapp, foo, condition);
with:
break -probe-stap myapp:foo if $_probe_arg0
I was shown a sample program to demonstrate recursion which looks like it should not work but does. The logic is pretty clear but why does it work even when the recursed function call is not returned? It seems like the return command breaks out of the stack even if it isn't requested to. Is this a language standard or a gcc thing? I saw it with C and C++ compiled with gcc on Windows and Linux.
#include <iostream>
#include <cstdlib>
using namespace std;
int isprime(int num, int i)
{
if (i == 1) {
return 1;
}
else {
if (num % i == 0)
return 0;
else
isprime(num, i-1); // should be returned
}
}
int main(int argc, char** argv)
{
int input = atoi(argv[1]);
cout << input << "\t" << isprime(input, input/2) << "\n";
}
Things like that only work if accidentally the return value happens to be in the register where the caller expects it. This only works if this is realized by your compiler as a recursive function. Technically it is undefined behavior to use the return value of a function that doesn't provide one.
Edit: On modern architectures the return value of a function for values for which it is possible is passed in a specific hardware register. When you call your function recursively, on the bottom in all cases that hardware register is set to the expect value. If by chance when popping up from recursion that hardware register is never changed, you end up with the correct value.
All of this pattern wouldn't work, if the return value would be placed at some location of the stacks of the (recursive) callers.
In any case, all of that should be captured by any modern compiler and give you a warning. If it doesn't you don't have a good compiler, or you are using too defensive command line options.
New year's eve special: In the real world, code like this (with the return) wouldn't even be realized as a recursive function. With not too much effort you will find an iterative variant of that function, and any modern decent compiler should be able to find it as well if you ask for maximal optimization.
A lot here depends what you mean by "it works"?
to try and answer the main point of your question, functions will return when the end of the function is reached, whether or not a return statement is met.
I would expect to see compiler warnings telling you the possible controls paths may not return a value, in C++ at any rate. Resulting in undefined behaviour, see this question:
not returning a value from a non-void returning function
I would say that this example "works" as after a prime is found and isPrime has returned, then the next function up the stack is also free to return. Nothing depends on the return value of isPrime either, so the program will run back up the stack and output something.
...but as behaviour is undefined, the value that actually gets output is likely to be junk. If you are seeing 0 & 1 consistent with primes as input, then wow.
If you think this is working, I would look at testing more broadly with different values.
Also have you been building with any "debug" settings? if so try this again with debug settings off, as thiese sometimes do extra work to keep things uninitialised memory clean.
I can explain exactly what happens:
The function is called, and it recurses back into itself until it reaches the return at either modulo (return 0) or end of recursion (return 1). At this point the function reuturns to the caller, which is is_prime. But there is no more code in the function to execute, so it immediately returns without any further action.
However, you could easily break this by, for example, add printf("Done for %d, %d\n", num, i); behind the call of is_prime() [doesn't have to be in the if-statement]. Or adding a C++ object that is created and destroyed on entry/exit of the function, as another example.
You're just being lucky that it works. And it's very fragile and easy to break - compile it with a different compiler (or with different optimization settings, or a new version of the compiler, or a million other things), and it may well break.
Aren't you forgetting a return statement? For normal recursion you need to put a return before isprime(num,i-1); as well.
I guess this even should give a compile warning if you compile this using strict rules, because the function must always return an int, now it does not (at least if your compiler does not fix this).
class CCtrl
{
...Other Members...
RankCache m_stRankCache;
uint32 m_uSyncListTime;
};
int CCtrl::UpdateList()
{
uint32 tNow = GetNowTime();
for (uint8 i = 0; i < uRankListNum; i++)
{
m_stRankCache.Append(i);
}
m_uSyncListTime = tNow;
return 0;
}
Here are two weired things:
When step into Append(), p this = 0x7f3f467edfdc, but in UpdateGuildList(), p &m_stRankCache = 0x7f3f067edfdc, these two pointers are different.
tNow = 1418916316, after executing m_uSyncListTime = tNow, m_uSyncListTime is still 0.
How could this happen? I've used a whole day for debugging. And I checked my code there is no pack(1) and pack() mismatch.
The issue is more than likely that you're using your debugger to debug code that has been optimized. As your comment suggested, you are debugging code that has been compiled with the -O3 flag, denoting optimization.
Even though you're using gdb, the Visual Studio and other debuggers also have the same issue, and that issue is debugging optimized code and having the debugger "work" in the sense that the debugger follows along with the lines in the source code, along with the variables that have been declared.
A debugger assumes that the lines of the source code match up with the generated assembly code. With optimizations turned on, this can no longer be the case. Code and variables are eliminated, moved, etc. Therefore the lines in the code (including variable declarations) you believe should be there at a certain location may not be there in the final optimized build.
The debugger cannot discern these changes, thus you get erroneous values used for variables, or in some cases, you get "variable doesn't exist" errors reported by your debugger.
Also, it may also serve as a good check to do a simple cout or log of the values in question if there is a problem with the debugging environment. There are situations where even debuggers may get things wrong, so a backup verification system (i.e. logging, printf() or cout statements, etc.) should be used.