You are not logged in. You can browse in the PowerBASIC Community, but you must click Login (top right) before you can post. If this is your first visit, check out the FAQ or Sign Up.
I have a program that uses GOSUB/RETURN but I get an execption at the RETURN.
Does anyone know how I can check the return address so I can see when it is getting corrupted?
What kind of exception? Stack fault? page fault? Invalid opcode? NUmeric overflow?
Just FWIW (and in this case it is worth a lot).... just because your program fails with a general protection fault after executing some line of source code does not mean the underlying memory corruption (if that is the problem) occurred sometime between the last executed line and the fault; the 'real' error may have occured elsewhere in in your program, hundreds or even thousands of executed lines ago.
There is a FAQ on using TRACE to find instances of "error 9" in the FAQ forum which can be really handy in this case.
PB's GOSUB/RETURN works; do not look for potential compiler problems here because it will be a total waste of your time. As Shakespeare has written...
The problem, dear Brutus,
Is not in our stars,
It is in our selves.
Make sure you are not executing a RETURN without a GOSUB this will cause a Memory Access Violation exception. Step through your program in the debugger and I am sure you will find the cause.
I am getting an %EXCEPTION_ACCESS_VIOLATION trying to read data.
Because it happens on the return I'm guessing the stack is being corrupted somewhere between the beginning of the gosubbed code and the return point. I am just wondering if it is possible to monitor the return address to see when it changes.
I tried the error checking from the FAQ but didn't get any error logged.
Because it happens on the return I'm guessing the stack is being corrupted somewhere between the beginning of the gosubbed code and the return point.
Please re-read what I said. That is a bad assumption.
Yes, it is possible the stack is being corrupted. It's also possible it's not.
It's possible the corruption is in fact occuring between the GOSUB and the RETURN. It's also possible the corruption is occurring elsewhere... somewhere you think it just not possible to occur.
Your best bet at this point is to post the code from the GOSUB'd label through the RETURN and see if a fresh set of eyes can spot something. But don't be surprised if that only leads to requests to post additional code, because it is by no means a certainty the corruption is occurring in this particular snippet.
BTW, see the CALLSTK function if you are convinced the problem is with your stack.
I'm not sure that handles GOSUB/RETURN, but you could just restructure
Code:
GOSUB Foo
...
foo:
code
code
code
RETURN
.. to use
Code:
CALL Foo (variables needed by subroutine as parameters)
...
...
FUNCTION Foo (variables needed by subroutine as parameters)
code
code
code
END FUNCTION
.. and now for sure CALLSTK will give you a good trail as to how you got to where you are.
If your coding metabolism is anything like mine the very act of simplifying your code to make an example of the problem to post in this forum will probably lead you quickly to a resolution. If it does not, people here will fall upon your code like a pack of wolves and tear the error out of it. Good luck!
I see no update on this post. I seriously doubt that it casts doubt on how PowerBasic compilers handle GOSUB and RETURN operations. These compilers have been tested time and time again, and we all know how stable and reliable they are.
Anyone using GOSUB and RETURN rather than a SUB, EXIT SUB, END SUB tends to suggest someone not yet well versed in all the power and options presented by PowerBasic. That PowerBasic supports GOSUB and RETURN still is a testament to their commitment to let programmers program as they choose. But the structure and automatic error checking inherent in using formal procedures like SUB and FUNCTION make them the preferred method of coding redundant processes. The risk with GOSUB and RETURN is that these may not mate up correctly in spagetti code, and this can be a major problem to isolate and resolve.
Any call structure, whether GOSUB, RETURN, CALL, or EXIT (sub or function) effect the contents of the stack. Further, for SUBs and FUNCTIONs, passed parameters and local variables also are assigned space on the stack. GOSUB and RETURN are going to modify the stack, or stack pointer, any time they are used. And when the two do not balance each other out, the stack will be corrupted. Which is why we don't use them much any more. It puts too much responsibility on the programmer to get the code esactly right, and not jump to false conclusions when it blows up.
Anyone using GOSUB and RETURN rather than a SUB, EXIT SUB, END SUB tends to suggest someone not yet well versed in all the power and options presented by PowerBasic.
Anyone making the above assumption tends o suggest someone not yet well versed in the online help for GOSUB, from which I quote:
For time critical or high-performance code, using a GOSUB to perform a repetitive task is almost always faster then performing a call to a Sub or Function, since there is no overhead in setting up a stack frame for a GOSUB
I personally stay away from GOSUB on the sheer reason that for each one, its just as easy (if not easier) to create a function from the common routines, that other functions may be able to use at a future date (aka, if I write it, and realize I am duplicating the core idea in each function, with a slight twist, then I make the core idea a function, and code for "What-If" twist)
that and it eliminates a lot of "Hard to Find" bugs, that can not be solved by messageboxes, or logging errors, because just the messagebox, or the log being written, could allow enough time (and enough other functions) to correct the error that originally occurred and making it harder to find.
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
I personally stay away from GOSUB on the sheer reason that for each one, its just as easy (if not easier) to create a function from the common routines, that other functions may be able to use at a future date (aka, if I write it, and realize I am duplicating the core idea in each function, with a slight twist, then I make the core idea a function, and code for "What-If" twist). ...
I use GOSUB/RETURN to maximize the speed of my reusable procedures. I limit them to inside procedures (with an "EXIT procedure" line as a fall-through barrier).
It's handy with some of the things I use over and over. So far the debugger's step through option has been sufficient for my needs when I encounter suspect GOSUBs.
Stan
Do not go quiet into that good night,
... Rage, rage against the dark.
Maybe an interesting addition would be local functions/subs (i.e. visible only to the function/sub in witch they are declared), with (eventual) parameters passed on the registers.
Bye!
-- The universe tends toward maximum irony. Don't push it.
GOSUB calls share all the data and variables visible where the call is made. There is no distinction from variables and data handled by the called gosub rountine. SUBs and FUNCTIONs only share what is global or passed to/from them. Between recursive and repeated calls to a SUB or FUNCTION, static variables retain their values. Local variables are assigned space on the stack and set to zero on each call.
Speed is not everything. The added methods of handling data and isolating variables can really be used to an advantage. When developing code, SUB and FUNCTION are much easier to deal with as modules, rather than the distributed calls that you have with GOSUB and RETURN. They even help further in debugging because you have the option to step into, step over, or step out of either a SUB or FUNCTION. Not so with a GOSUB and RETURN implementation.
If you want even faster speed, then you would be arguing that MACROs are the only way to go. Every technique has its positives and negatives. Like GOTOs, GOSUB and RETURN imposes some peril and responsibility on the programmer, and it it ends up in a thread like this, I would have to say it is because the user simply did not appear to know this.
I've used GOTO, GOSUB, and similar branches many times, because I know that they have their place. The primary reason for using GOSUB is not to go fast (which it does), but because you want the embedded code to act on the variables and data that it holds in common with the calling process. That's all. Otherwise, you end up having to pass a lot of parameters back and forth to no real purpose. On the other hand, you can make the items to be shared GLOBAL in nature, meaning that they are accessible at all levels of your code. It's something of a judgement call in which way to go.
GOSUB is VERY handy when you need time-critical code that must branch to the same routine at least once. The speed difference using GOSUB rather than setting up/releasing a stack frame (when calling a FUNCTION) in looping code is astounding. There is no point comparing GOSUB to GOTO <label>, CALL <FUNCTION>, or CALL <SUB>, as it is completely different.
MACRO is the closest you will get to GOSUB, but sometimes it's nice to keep all related code in just one procedure with two or more GOSUB branches. Of course, it can be abused (as with most branch statements, such as GOTO), but that is usually due to the programmer's inexperience. My first large BASIC program used many GOTOs/GOSUBs, but I learnt from it when it got harder to understand the code later on.
I just took some of the medicine which I prescribed for Donald Darden and actually read the help on GOSUB, all of it, word by word. I usually skim reading matter, but since my spectacles got weaker this is not without hazard.
What it also says is:
Note that ON GOSUB (and ON GOTO) have been internally optimized to produce greater run-time performance than was possible with previous versions of PowerBASIC
I'm not familiar with previous versions so I don't know when that sentence was added, was it version 8? 7? or what? And what was actually changed? Just curious.
When I use GOSUB - in search of better performance as it happens - I follow Mr Zale's advice:
Each subroutine should end with RETURN, which causes execution to resume with the statement immediately following the ON GOSUB statement.
But given that the GOSUB operates within it's "parent" SUB or FUNCTION stack, wouldn't it also be safe to EXIT SUB or EXIT FUNCTION from within the GOSUB?
Yes, it's perfectly safe to EXIT a function without a RETURN to a GOSUB. PowerBASIC handles all the messy details for you. That said, I just can't bring myself to write code that way. It just has no symmetry. {smile}
The biggest mistake folks make with GOSUB/RETURN is "falling-through" into the subroutine, which executes the RETURN without a prior GOSUB. That's a guaranteed GPF.
Code:
SUB abc()
GOSUB Routine
' do something
Routine:
' do something else...
RETURN
END SUB
The problem here is that the RETURN is executed twice. The code needs an EXIT SUB just before the label "Routine".
The biggest mistake folks make with GOSUB/RETURN is "falling-through" into the subroutine, which executes the RETURN without a prior GOSUB. That's a guaranteed GPF.
We process personal data about users of our site, through the use of cookies and other technologies, to deliver our services, and to analyze site activity. For additional details, refer to our Privacy Policy.
By clicking "I AGREE" below, you agree to our Privacy Policy and our personal data processing and cookie practices as described therein. You also acknowledge that this forum may be hosted outside your country and you consent to the collection, storage, and processing of your data in the country where this forum is hosted.
Comment