Catching bugs
Alone Coder
Inspired by the PVS-Studio blog on the Hub─
re, I decided to try to find the most typical ones.
errors that arise during development
TKA in Z80 assembler.
I would like to believe that this will help
increase coding efficiency on ZX
Spectrum. In addition to practical advice, we can─
but in the end, make and utilities con─
trolling source codes (even if built into
assembler), which will find the most typical
errors. And not in the sense that it’s coding─
It would be a mistake to act somehow “outside the box.”
Warnings will simply be issued
if the suspicious code is not marked somehow
especially. The warnings have long shown themselves
a good tool in bo compilers─
than other systems. They allow, for example─
measures, find the error"=" instead of "==" in C or
some triggers on two fronts in
Veriloge (knowledgeable people will correct).
I don’t know why we write so little
about dealing with errors - probably immediately─
It seems that cool coders don't make mistakes─
side (Like cool artists who supposedly
they draw without erasing and immediately get it white.) This, to─
Of course, that's not true. Searcherrors takes up
in any case, no less time than writing─
knowledge of the code. But if the work is built correctly,
then you can debug without nerves and
almost not notice it.
And how to do this?
There are evidence-based program methods─
developments described in smart books (such as
Robert L. Baber.Error-free Software. Know-
how and Know-why of Program Correctness).
There are functions (not above a certain level difficult─
sti) are checked by ingenious methods, but,
I'm afraid not for you and me. It's good for
those cases when the program is already on the first
startup should work like a clock, and the time
allocated for development with a reserve for everything
proof and double-check (because proof─
functions are almost more complex than themselves
functions).But we have a different case - we can
run the program whenever and for as long as you want
anything, and she won't ruin anything.
Let's look at the situations:
a)you need to write a new program;
b)you need to redo your program;
c)you need to redo someone else's program.
Let's start witha). It's good to write a program
if you know its entire structure in advance. Himself
coding by itselftakes little time
compared to design. They say about─
professional programmer writes 30 lines
debugged code per day (there were more than
Simistic assessments, including from everyone from─
famous Frederick Brooks). If there is all
structure and clearly understand what procedure is what
should do, then we can check each
procedure separately. Maybe even a car─
matize this functional testing─
tion, if we gather the program regularly
redo - here we move on tob). This
it’s good when the program is large, developed─
There are a lot of people and you can’t keep track of them all. If
along with each procedure there is a check─
this procedure, and before each assembly everything
these checking procedures are called, then
you can control that no one knows anything─
I didn't accidentally break it. This is alreadyc).
But again: the methods are good, but not for
our tasks. We can rebuild the program─
as much as you want and whenever you want, at least
after every change. And not only can we, but
that's how it should be done. Small step, compi─
lation, launch, catch a bug - and a bug with ver.
95% certainty is in the newly added
code, you don't even need a debugger.
But to take this step, we need
so that the original version of the program is itself
in itself workable. From here follow
conclusions point by pointa), b), c):
a): primarily when developing pro─
grams need to be built at least some work─
capable skeleton, which can then be
change gradually. For example, ACEdit in devi─
honor was leafing through texts under 48K, sleep─
started even without disk operations.
b): it is necessary to interrupt the development of the program
required on a working version, otherwise─
Why can’t you pick it up or raise it later─
you move with disproportionately great difficulty. Zhela─
It’s also important to document how it’s created─
army. Too lazy to document or do
car assembler? This is how the Awaken project died.
c): if you need to remake someone else’s program─
mu, then first you need to make sure that it is com─
sawed and works without modifications. If
this alteration involves transfer to another─
goy assembler or decompilation, then for─
first we need to check that after such a re─
everything is compiled into a block of code, byte by byte─
but identical to the old one.
Spherical algorithm for such a modification
programs:
1.Ensure that it compiles (not
fact that is correct).
2.Get it to work (according to─
twee with the old version).
3.Get it to work as it should (with
new changes).
4.Get it to work as it should─
completely (beta test is desirable).
When remaking source codes from friends
systems and development tools the first two pu─
nkta are fulfilled at the very beginning.
Specifically, the sequence of work when
decompilation (I speak from my own experience with Pro
Tracker 3 and Perfect Commander):
1.Decompile (with clear separation
code and data). I'm using ZXD.
2.Go through the entire source from top to bottom
and take notes.
3.Place normal marks and calculate─
expressions. When we replace a label in
procedure, we can use error messages─
How to find out how many requests there were to it.
This can be noted and then used in
optimization.
4.Check that the compilation result
byte to byte matches the pattern. I am─
I use the File Comparer utility by MAYhEM
(FCmp_v2BonSYS.TRD).
5.Make sure that whenadding to the beginning
but someDS 300program is still
works.
6.Only then start making changes─
nia (possible inIF's, through a conditional computer─
lation).
* * *
So, let us learn to work a little─
in small steps. We build a skeleton from knowledge─
which procedures and familiar methods, then
step by step we add functionality, inter─
face, optimize, etc. Sort of Agile. But
despite the fact that 95% of glitches are located
immediately (including by the compiler), remains
5% of those that need to be scratched over─
woo.
There are two main ways to catch glitches:
1.Check everything. Namely, what is wrong─
no, and the code that depends on it. And at the same time
the code called from there.
2.Make a test case (that is, break it).
I usually use the second one. I find a test─
a case that is definitely buggy (you can do
special conditions right in the program, which─
I would like to go to the branch), I trace it or stupidly
I look at the variables.
For example, we are writing a 3D engine. Done
somehow, we twist and turn, and then BAM - what is it
flashed? How to repeat this? And this is for─
hangs from how we twisted. If they were twisting
automatically, you just need to findnumber
frame (for example, we trace frame by frame
and look). If from the keyboard, then you have to
look at the parameters and especially check under─
visual combinations (for example, with zero
angles, with maxima or minima of mass─
headquarters). Personally, I prefer to spin the car─
mathematically until I debug the rendering. Upra─
I insert the input from the keyboard later, only
for complex trajectories and not always. So, in
Critical Error, The Board and The Board II
there was keyboard control, and in Mission
Highly Improbable and New View 48K were about─
written scripts. And at first I’m an automaton─
I’m tactically twisting, let’s say, one polygon and
one axis (or moving one vertex), only
then I add and check other movements,
combinations of polygons, etc. So that when bu─
future optimizations will not ruin what is already
debugged, I save these old tests in ve─
conditions of conditional compilation. If the program
suddenly stopped working, you can always
go back in seconds and check it for
simple cases.
By the way. One good uncle (or maybe
angry) wrote somewhere on the Internet, and I’m talking about─
I quote to you: "You solve a problem, and
produce beautiful,understandable code.Then
you optimize and produce a big ugly chunk
of WTF.Keep the original code in comments"
("You solved the problem and got a beautiful,─
clear code. Then you optimized it andwe got a huge piece of something unknown.
Leave the original code in the comments─
yah"). I often use this principle.
I am creating an algorithm in a high-level language─
nya (sometimes I even debug in Delphi), kla─
dude him in the comments and on these comments─
I'm writing optimized code. I did this
and in C, when Billiard wrote: sometimes horror,
which generated SDCC can be accelerated in
times with assembler inserts, but before these─
with assembly inserts it would be better to remain─
Post the original code in the comments. If
Since I initially write in assembly language, then
I have a text document where in general
outlines the method and several options─
tov of its implementation. If I change one code
on the other, then I do it through a conditional
compilation, and then, if necessary, clean
Well, I also save the old version somewhere.
Yes, don’t try to implement windows right away─
final method. You still have the skeleton of the program
didn't work, but already "big ugly chunk of
WTF", which needs to be debugged entirely. Sleep─
let it work somehow. For example,
through the point procedure in ROM. Through attributes
instead of chunks. Without texturing. With branches─
using checks rather than using a table. Etc.
Here you can also remember that “it’s premature─
Nayaoptimization is the root of all evil."
I wrote colored chunks for New View 48K
immediately in its entirety and without debugging. Ulo algorithm─
lived in713 lines - it would seem not much.
As a result, on the first try it starts─
I had to find and fix it19 ba─
gov, of which 3 were design errors.
vania (including those related to the number of strokes─
hovok).
And the most difficult glitches are combinations
two or more.
(for practice, see the next article)
Share your thoughts about the article