Pointers and memory access
Pointers
Using pointers is possible by placing one * in front of the name of the variable. A pointer is a variable that stores a memory address and which is generally associated to a structure.Example:
*MyScreen.Screen = OpenScreen(0, 320, 200, 8, 0) mouseX = *MyScreen\MouseX ; Assuming than the Screen structure contains a MouseX fieldThere are only three valid methods to set the value of a pointer:
- Get the result from a function (as shown in the above example)
- Copy the value from another pointer
- Find the address of a variable, procedure or label (as shown below)
Note: Other than in C/C++ in PureBasic the * is always part of the variable name. Therefore *ptr and ptr are two different variables. ptr is a variable (regular one) storing a value, *ptr is another variable of pointer type storing an address.
Pointers and memory size
Because pointers receive only addresses as values, the memory size of a pointer is the space allowing to store an absolute address of the processor:
- On 32 bits processors the address space is limited to 32 bits, so a pointer takes 32 bits (4 bytes, like a 'long') in memory
- On newer 64 bits processors it takes 64 bits (8 bytes, like a 'quad') in memory, because the absolute address is on a 64 bits range.
As a consequence the type of a pointer depends of the CPU address mode, (‘long’ on 32 bits CPU and ‘quad’ on 64 bits one for example), so a pointer is a variable of type pointer.
It results from this that assigning a type to a pointer (*Pointer.l , *Pointer.b …) makes no sense.
Note:
- Every time a memory address needs to be stored in a variable, it should be done through a pointer. This guaranteed address integrity at the compilation time whatever the CPU address mode is.
- PureBasic does not generate 64 bits executable yet. As long as PureBasic programs are 32 bits compiled, the system accords them only a 32 bits length addressing.
Pointers and structures
By assigning a structure to a pointer (for example *MyPointer.Point) it allows to access any memory address in a structured way (with the operator ‘\’).
Example:
Define Point1.Point, Point2. Point *CurrentPoint.Point = @Point1 ; Pointer declaration, associated to a structure and initialized with Point1's address *CurrentPoint \x = 10 ; Assign value 10 to Point1\x *CurrentPoint.Point = @Point2 ; move to Point2's address *CurrentPoint \x = 20 ; Assign value 20 to Point2\x Debug Point1\x Debug Point2\xPointers allow to move, to read and to write easily in memory. Furthermore they allow programmers to reach big quantities of data without supplementary cost further to data duplication. Copying a pointer is much faster.
Pointers and character strings
All variables have a permanent size in memory (2 bytes for Word, 4 bytes for a Long, etc.) except for strings variables with lengths that can change. So string variables are managed by a different way of other variables.
Thus a structure field, that makes reference to a string, store only the memory address of the string instead of the string itself: a such structure field is a pointer towards a string.
Example:
Text$ = "Hello" *Text = @Text$ ; *Text store the address of the string in memory *Pointer.String = @*Text ; *Pointer points on *Text Debug *Pointer\s ; Display the string living at the address stored in *Pointer (i.e. @Text$)Pointers Arithmetic
Arithmetic operations on the pointers are possible and practical by using SizeOf().
Example:
Dim Array.Point(1) ; Array of points *Pointer.Point = @Array() ; Store the array address *Pointer\x = 10 ; Change the first array element values *Pointer\y = 15 *Pointer + SizeOf(Point) ; Move to the next array element *Pointer\x = 7 ; Change the second array element values *Pointer\y = 9 ; Display results For i = 0 To 1 Debug Array(i)\x Debug Array(i)\y Next i
Addresses of variables
To find the address of a variable in your code, you use the at symbol (@). A common reason for using this is when you want to pass a structured type variable to a procedure. You must pass a pointer to this variable as you cannot pass structured variables directly.Example:
Structure astruct a.w b.l c.w EndStructure Procedure SetB(*myptr.astruct) *myptr\b = 69 EndProcedure Define.astruct myvar SetB(@myvar) Debug myvar\b
Addresses of procedures
For advanced programmers. The most common reason to get the address of a procedure is when dealing with the OS at a low-level. Some OSes allow you to specify callback or hook functions (for some operations) which get called by the OS and allows the programmer to extend the ability of the OS routine. The address of a procedure is found in a similar way to variables.Example:
Procedure WindowCB(WindowID.l, Message.l, wParam.l, lParam.l) ; This is where the processing of your callback procedure would be performed EndProcedure ; A special callback for the Windows OS allowing you to process window events SetWindowCallback( @WindowCB() )
Addresses of labels
It can also be useful to find the address of labels in your code. This can be because you want to access the code or data stored at that label, or any other good reason you can think of. To find the address of a label, you put a question mark (?) in front of the label name.Example:
Debug "Size of data file = " + Str(?endofmydata - ?mydata) DataSection mydata: IncludeBinary "somefile.bin" endofmydata: EndDataSection