FB II Compiler

PG PRO

Debugging

Memory

System

Mathematics

Resources

Disk I/O

Windows

Controls

Menus

Mouse

Keyboard

Text

Fonts

Drawing

Sound

Clipboard

Printing

Communication

ASM

Made with FB

FB II COMPILER

Know more on using XREF@


If I understand your question right, you want XREF@ ARRAY%(5,_BIG):

Pretend memory:
abcdefghijklmnopqrst

ARRAY(5,4)
abcde
fghij
klmno
pqrst

ARRAY(4,5)
abcd
efgh
ijkl
mnop
qrst

So if _BIG is your impossibly huge number, you may never get to the end of your first row:

ARRAY(_BIG,5):
abcdefghijklmnopqrst

You have only one partially valid row, so any reference to ARRAY(1,1) is past the end of the handle.

ARRAY(5,_BIG):
abcde
fghij
klmno
pqrst

You have only four valid rows, but you can refer to ARRAY(0,0), ARRAY(1,1), and even ARRAY(3,4) and still be inside the handle

Greg


The rightmost subscript is the one that increases most rapidly as you step through memory. In other words, the elements are stored in this order:
(0,0)
(0,1)
(0,2)
:
(0,n)
(1,0)
(1,1)
:
etc.

This is easily verified by printing out the addresses of a few array elements.

<< In order to XREF it, I need to specify the size of the array ahead of time. Since I don't know how big the Array needs to be ahead of time, I have to specify the one array dimension as being impossibly huge. >>

Actually, as long as you don't have the "Array overflow checking" preference turned on, the leftmost subscript in an XREF@ declaration is totally ignored (except that the compiler requires that it be greater than zero). So you could declare it as follows:

XREF@ ARRAY%(1,5)

and still reference elements like ARRAY%(17,2), etc. with no problem. This works because XREF@ doesn't really need to know how big the array is (since it doesn't allocate any space for it)--it just needs to know where it starts, and what its internal structure is. The 2nd through "nth" dimensions have to be specified correctly in order to declare the internal structure, but the first dimension is irrelevant to that.

<< If I want the 5 values to stay next to each other in memory...
XREF@ ARRAY%(5,_BIG) ' Make Array Useable...
...or:...
XREF@ ARRAY%(_BIG,5) ' Make Array Useable... >>

If it's actually groups of _five_ that you want to stay together, and assuming you're using he "array element zero" preference, then you should probably do it like this:

XREF@ ARRAY%(_BIG,4)

That's because your five elements will be numbered 0 through 4. Again, if you have "array overflow checking" turned off, the above is equivalent to this:

XREF@ ARRAY%(1, 4)

Rick


<< Can I use an XREF'ed array to hold Handle Addresses for other XREF'ed Arrays? >>

What the XREF statement does is tell the compiler, "I'm going to give you the address where an array starts. Now you set it up so I can look at it _as_ an array." It doesn't care what's in that memory space; it will just spit it out in whatever size chunks your XREF statement tells it.

<< XREF@ CLDES%(7,_CPMAX) >>

I believe it's usually safer to do this the other way around:

XREF@ CLDES%(_CPMAX,7)

The compiler doesn't care what the first parameter is, only the later ones. The way you had it, the compiler set up your array to look at an indeterminate number of (_CPMAX+1)-element arrays. The other way, it looks at an indeterminate number of 8-element arrays. Even if it really doesn't matter, conceptually I'd rather deal with that. It also allows you to see all 8 values together in MacsBug, rather than scattered over vast distances.

<< The array appears to work properly, but perhaps the compiler gets confused with it under some circumstances and reads/writes data to the wrong location? >>

Sorry, but the compiler will do only what you tell it to. You may be able to confuse you or me, but not it.

<< If I use the debugger to show the contents of the 2nd array, it shows only bogus (and unchanging) values. >>

The debugger, I believe, shows only addresses for XREF@ data, no values. You have to go into MacsBug to see what the values are. If that's what you're doing, and you're still seeing different things from what you expect, I suspect you may have either passed XREF a handle, or passed XREF@ a pointer. Another thing to look for is an XREF or XREF@ statement where you've accidentally put a "&" instead of a "%" after the var name. That will instantly double the size of your array and probably overwrite other data, but could seem to work fine while doing so.

One thing you might try is making a record of the start and end (max) addresses for each XREF array as you step through, to see if you can find any overlap. Since handles can move around, this wouldn't be proof, but it sure might be a starting place. You can also compare these with the address and size of the block to see if they correspond.

As a matter of form, I always put my XREF statements directly under the corresponding DIM statements, before I put a handle (or ptr) in the var. I don't think this will make a difference, but it couldn't hurt to try.
e.g.,

DIM CLDES&
XREF@ CLDES%(999,7) 'I use 999 to remind me FB doesn't care
CLDES&=gCLDES&
LINK%=CLDES%(N%,LINKNUM%)

I'm a little leery of your terminology, "the address of a handle." If this means the handle itself (what I call the address of a pointer), then you're okay. If you're talking about the address where that handle is stored, then you may have a problem.

One other idea: I notice you have local and global vars of the same name (except for the g). Is there a possibility there could be an extra or missing g anywhere? Are you using _DimmedVarsOnly?

<< Even so, I've poured over the code for days now and there's nothing left to grasp at but straws like these. >>

We've all been there. This one should be solvable. If you can extract some code where you have made recent changes or where you are most suspicious of trouble, I (and perhaps others, too) would be happy to look at it. Just send it privately. (If the whole proj. is under 1mb, you can send me the whole thing and just tell me where _you_ think I need to look.)

Jay


As Jay pointed out in another post, you almost certainly want to switch your subscripts around like this:

XREF@ CLDES%(_CPMAX, 7)

If you do it as you wrote above (7,_CPMAX), then the compiler expects (for example) CLDES%(0,5) and CLDES%(1,5) to be separated by 2*_CPMAX bytes, which is probably not the way you have your data stored in memory. Indeed, this could very well be causing your crash: if you have defined _CPMAX too large, then setting or reading CLDES%(s1,s2) could be referencing some memory address way out in the stratosphere. Specifically, the compiler looks for CLDES%(s1, s2) to be at 2*(s1*_CPMAX + s2) bytes past the address of CLDES%(0,0). You do the math.

Keep these rules in mind when declaring XREF[@] arrays of 2 (or more) dimensions:

* The value of the 1st dimension is ignored (except that it must be >0; a compiler peculiarity);
* The values of the 2nd and subsequent dimensions must _exactly_ match the way your data is laid out in memory.

So, the value of the 1st dimension is unimportant; the values of the 2nd and subsequent dimensions are very important; they must be neither larger nor smaller than the "matching" dimensions in your actual data.
If you want to set one of your dimensions arbitrarily large, it must be the 1st dimension.

I think Dave's handle was smaller than the space taken by a _CPMAX x 7 array--If I remember right, he purposely set _CPMAX to be larger than the largest subscript value that would actually be used in that position. As I mentioned in another post, that seems innocent but can get you into trouble: the _first_ dimension in a multidimensional XREF[@] can be declared arbitrarily large (or small); but the 2nd and subsequent dimensions are not arbitrary. The 2nd and subsequent declared dimensions are used when FB calculates where a given array element is supposed to be relative to the beginning of the handle. For example, if you have a 2-dimensional integer array declared like this:

XREF@ myArray%(_const1, _const2)

then the offset of element myArray%(s1, s2), relative to the beginning of the handle, is calculated as:

2 * (_const2 * s1 + s2)

You see that _const1 is not even considered in this calculation. On the other hand, if you make _const2 too large, then myArray%(s1,s2) could reference an address outside the handle's bounds, even for small values of s1 and s2.

Rick


<< However. I never use XREF, not it's @ cousin, as they seem too much fuss. What's wrong with grwowing your own handles, then you can check, length and overwriting, and you know where you are?
XREF just seems a level of indirection that can create confusion and error... As this original post would imply... >>


I respectfully disagree. XREF@ adds structure, not indirection. It's simply the elegant way of doing exactly what you are suggesting. Granted, you still have to do the checking, but you have to do that in any case.

Essentially, what the XREF statements do is allow you to use FB's robust array-handling routines on memory that you specify, rather than on memory that you explicitly allocate with a DIM array(10,20) statement. It eliminates the need to pass (i.e., copy) arrays between functions, because you can just pass their handles (or pointers).

I'd bet an icecream cone (2 scoops!) that for regular-length data (%, &, etc., or records), my XREF@ code will be shorter and probably more elegant than your "home-grown" handle code.

Jay (more below)

===============================

<< I define a record...
DIM RECORD testRec
DIM testFirstEntry%
DIM testSecondEntry&
DIM 25 testThirdEntry$
DIM END RECORD.testRec

Then I use ( 3*_testRec + _testThirdEntry) type constructions the put and get the info in the handle. This seems as intuitive as I need. I'm not saying XREFs is not good, just that they seem to create confusion (would they be a hangover from a time when there was no support for handles and pointers in FB?) and thus I have never perceived that the gain I could obtain from using them would exceed the investment in time and grey matter to grok and debug the little thingies (This is of course a reflection on the bad quality of my grey matter, not on XREF, but my point was that if others have similar 'conceptual' problems with XREF, there are other techniques...) >>


And if you need 1000 entries? I know you're not short on gray matter, but maybe you need a primer:

You understand arrays, yes?
You understand handles and pointers, yes?

XREF and XREF@ merely put arrays into pointers and handles, respectively.

To use XREF@,

'1. Set up variables to hold handles
DIM myXArray&, myHandle&

'2. Allocate some space for the array.
'Let's assume 100 Long integers,
' so the size needs to be 100*4 = 400
myHandle& = FN NEWHANDLE(400)
'You would do this to grow your own
'anyway

'3. Dimension the array using XREF@ (exactly like a DIM statement)
XREF@ myXArray&(99)
'Use same name, so FB knows which handle to use

'4. Tell FB where to find the array
myXArray& = myHandle&

You're done! myXArray&(n) is exactly like any other array you've ever DIMmed, except that it is located at [myXArray&]. (Which is also [myHandle&].)

What may get confusing is that if you want to use another (_any_other) array of long integers in a handle, you can do so just by providing the handle:

myXArray& = myOtherHandle&

This is the equivalent of BLOCKMOVEing one array into the space of another, except nothing has to be moved except the handle, and the original array isn't demolished in the process.

When you "grow your own," you're duplicating functions that are available in FB, and which have been tested and proven a lot more than yours.

I hope this adds more clarity than confusion.

Jay


<< I don't think you can even XREF record variables anyway, just shorts and longs. >>

Nope. Please see my XREF@ Arrays Demo which uses _only- records.

You set it up exactly the same way you would set up a standard array of records--just replace DIM with XREF@ and provide the handle.

DIM myRGBArray&
XREF@ myRGBArray.6(99)

Put a handle into myRGBArray& and use the array just as if you had written

DIM myRGBArray.6(99)

Then, if you like, you can also set it up to address the individual values:

DIM myRandGandBArray&
XREF@ myRandGandBArray%(99,2)

If you put the same handle into both myRGBArray& and myRandGandBArray&, you can address the _same_ set of values either way you choose--as color records, or as R%, G%, and B% values:

myRandGandBArray%(9,0) = 27397 'Red
myRandGandBArray%(9,1) = 18452 'Green
myRandGandBArray%(9,2) = 29124 'Blue

colorRecord2Use = myRGBArray&(9)

Now colorRecord2Use (a 6-byte record var) containes the RGB you just defined (providing you gave both arrrays the same handle, of course).

Jay


Jonathan wrote:

<< I define a record...
DIM RECORD testRec
DIM testFirstEntry%
DIM testSecondEntry&
DIM 25 testThirdEntry$
DIM END RECORD.testRec

Then I use ( 3*_testRec + _testThirdEntry) type constructions the put and get the info in the handle. This seems as intuitive as I need. I'm not saying XREFs is not good, just that they seem to create confusion (would they be a hangover from a time when there was no support for handles and pointers in FB?) and thus I have never perceived that the gain I could obtain from using them would exceed the investment in time and grey matter to grok and debug the little thingies (This is of course a reflection on the bad quality of my grey matter, not on XREF, but my point was that if others have similar 'conceptual' problems with XREF, there are other techniques...) >>

When set up it is much easier to access record arrays than you are doing, just set as shown below:

_maxRecs = 100 'just for demo, can be any amount.
DIM gtestRecH& 'setup the handle for the array of records

XREF@ gtestRecH.testRec(_maxRecs*_testRec) 'can be any value, I usually
'setup just one record, then add other records
'as needed with SETHANDLESIZE.

'setup fake data for demo purposes
FOR d% = 0 to _maxRecs-1
gtestRecH.testFirstEntry%(d%) = d%
gtestRecH.testSecondEntry& = d%
gtestRecH.testThirdEntry$ = LEFT$(STR$(d%),24))
NEXT

Just use similar methods to access the array data. I also keep a track of how many data elements I have & what I am operating at the moment. Makes for easy display of a data record, anywhere in the array.

To increase(/decrease) the array just use the following method:

maxRec& = maxRec&+1 'increase num of records
currRec& = maxRec& 'set pointer records to newest
bytes& = maxRec&*_testRec 'set new amont of bytes for array of records
oserr% = FM SETHANDLESIZE(gtestRecH&, bytes&)

I hope this help your understanding of XREF@

Chris Wyatt