FB II Compiler







Disk I/O














Made with FB


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:

x& y% z

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:

rect 6 unnamed bytes a b c d

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:

rect a b c d

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:

t l b r

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:

t l b r

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 t
  DIM l
  DIM b
  DIM r

And I create a new record like;

DIM myRect.rectSize

I believe I get the same structure as above don't I? Namely,

t l b r


Not exactly. When you use DIM RECORD (at least, in the form you've shown above), then you are not actually declaring any variables called t, l, b nor r. Instead, you are really declaring some symbolic constants. The above DIM RECORD block is exactly identical to this:

_t = 0
_l = 2
_b = 4
_r = 6
_rectSize = 8

(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).)

When you you then create a record with "DIM myRect.rectSize", this is exactly identical to saying "DIM myRect.8", owing to the fact that _rectSize = 8. You now have this in memory:


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.

A small matter, but I prefer not to do the extra typing. BTW, there is a rect record already defined in the toolbox, so you could

DIM myRect.rectSize

then use the field constants myRect.top, myRect.left, myRect.bottom and myRect.right if you just want to make sure it's clear which rect you're addressing.


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.

To explain in more detail: All that FB does when you create a record is assign constants to its fields. In the myRect record, it gives t the value of 0, l=2, b=4, and r=6. It's the equivalent of doing this:


(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."

Suppose you were to DIM another structure, like this:

DIM myRecord
  DIM w
  DIM x
  DIM y
  DIM z

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:

PRINT myRect.y

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.

Records are incredibly flexible and amazingly useful.