FB II COMPILER
Understand the DIM statement
When you _don't_ use semicolons, then variables declared by DIM are placed "next to" each other in memory, according to the space required for each variable type. For example, when you do this:
DIM x&, y%, z.8
...then the location of variable y% begins 4 bytes past the beginning of variable x&, and variable z begins 2 bytes past that. It looks like this in memory:
But when you use semicolons, you're instructing the compiler to space variables differently. The syntax: DIM <var>;<constant> really means this: "Create space for variable <var> in the normal way (according to its declared type), but then advance <constant> bytes from the beginning of <var>'s location, and locate the _next_ declared variable there." The semicolon does _not_ affect how many bytes are reserved for the variable (that's determined by the variable's type)--it just affects how the variables are spaced in memory. You can use this fact either to make variables overlap in memory, or to push them farther apart. For example:
DIM rect;8, a, b, c, d
This causes memory to look like this:
The DIM statement said that "a" should be placed 8 bytes past the beginning of "rect," as shown in the picture. Note that rect is _not_ an 8-byte variable; it's a short integer, just like a, b, c and d. For some purposes (e.g. CALL SETRECT(rect,...)) we can treat it as if it were an 8-byte variable, because of the "extra room" that follows it; but for other purposes (e.g. "x = rect"; "PRINT rect") it looks just like any other 2-byte integer. Compare that with this:
DIM rect.8, a, b, c, d
In this case, rect is a true 8-byte variable, and memory looks like this:
Now, if you say: DIM <var>;0 you're saying, "Create space for variable <var> according to its declared type, and then advance _zero_ bytes past the beginning of <var>'s location, and locate the next declared variable there." This makes variables overlap. For example:
DIM rect;0, t, l, b, r
...makes the following picture:
In other words, "rect" and "t" occupy the same 2 bytes in memory. If you copy 8 bytes into the address where "rect" starts, you'll end up filling t, l, b and r, and this is why "rect" is sometimes considered a synonym for the rectangle defined by t, l, b and r in this case. It's probably slightly cleaner to do it like this:
DIM rect.8;0, t, l, b, r
Again, the ";0" causes "t" to be aligned with "rect," but now "rect" is a true 8-byte variable. That causes memory to look like this:
But it all depends on what you're doing: there are still some old FB Toolbox implementations that insist that you use a 2-byte variable for rect, even though the routines read or write 8 bytes. In those cases, the "DIM rect;8" syntax might be preferred over "DIM rect.8".
Now, if I say:
DIM RECORD rect
And I create a new record like;
I believe I get the same structure as above don't I? Namely,
_t = 0
(Technically, neither the DIM RECORD block nor these constant declaratations will compile, because "_b" happens to already be a pre-defined FB constant that equals 2. But let's pretend it's not, for this discussion).)
but no variables t, l, b nor r. Using the first method (DIM myRect.8;0,t,l,b,r) you are actually creating those variables; you could set, for example, the "r" field of the rectangle just by doing this:
r = 320
To do the analogous thing using the second method (DIM RECORD block), you'd have to do it like this:
myRect.r = 320
which really means: "Store 320 as a 2-byte integer into the address which is 6 bytes past the beginning of myRect." You would get exactly the same effect if you did this:
myRect.6% = 320
You can get the same job done using either method, but the syntax for doing it--and the situation in memory--is not the same for both methods.
Yes. Well, sort of. The difference this way is that in your code you can't refer to t, l, b, and r as separate entities, you have to use field constants: myRect.t, myRect.l, myRect.b and myRect.r.
Actually, you don't get a structure at all when you create a variable. All that the DIM statement does is assign 8 bytes of space for the variable myRect. The structure is something different that you use separately, to find the parts of your memory block that you are interested in. It's just a way to help you keep track of where you put things.
(This is why you would get a "redefined constant" error if you were to define a constant _r=1 somewhere else in your globals file). And when you type a statement like "myRect.b=72", you are telling FB to "place the number 72 four bytes from the start of the myRect record."
And suppose you didn't create any new variables at all but continued to use the myRect variable that was defined above. Now you could write:
and it would print the value 72 that was assigned above. This is because _y is a constant with the value 4, which is the same value that _b had. So when FB sees the myRect.y reference, it looks four bytes into the memory block that begins at myRect, just as it did before.