20 July 2010

Unsigned to signed Byte data type

GFA-BASIC 32 provides two unsigned integer data types, the Card and Byte data type. The Card is a 16-bits integer and allows you to store positive integral values in the range from 0 to 65535. The Byte is 8-bits data type allowing you store a positive value from 0 to 255.

It is not important how many positive numbers the data type can hold. More importantly is the way how these values are handled in case of mathematic operations. The default operation GFA-BASIC 32 allows on integers is signed arithmetic, because all other integer data types are signed types. However, when you include a value stored in a Card or Byte GFA-BASIC expands the value to an unsigned 32-bits integer before using it in a calculation. So, when you store 255 in a Byte, the value 255 is used in calculations.

Now, suppose you need to use a Byte to store values like: –1, 0, 1. (The GFA-BASIC 32 editor uses these values to store line indenting information and I used it to implement block folding.) You can simply store these values into a Byte and in case of –1 all bits of the byte are set resulting in $FF (=255).

Dim b As Byte = -1  ' b = 255 ($FF)

When the Byte is used in a calculation, the value 255 is applied, which is not what we want. We need the Byte to behave as a signed value; $FF must be interpreted as –1. For this to happen we must GFA-BASIC 32 tell to interpret the Byte as a signed byte explicitly using the Sbyte() function. The Sbyte(b) function forces a conversion to a signed expansion to 32-bits.

Dim b As Byte = -1  ' b = 255 ($FF)
i% = b           ' i% = 255
i% = Sbyte(b)    ' i% = -1

In fact, the compiler uses a different assembler instruction to move the value from memory to the eax register (movzx eax, mem).

02 July 2010

Accessing a C array

A C-compiler treats arrays as pointers. An array-variable points to the first element. C computes the address of an array  element by multiplying the element index with the size of the data type. This is
automatic behavior of C. A pointer is an 32-bits integer holding an address pointing to a specific type. For instance, the next declaration defines a pointer to an array of 16-bit integers. To be effective it needs to be assigned an address first.

short* parr;
parr = 0x0180980;

The variable parr references the Short (int16) at the given address. To read the value at the address:

short value;
value = *parr;

Incrementing the pointer with one will let the pointer reference the next element, not the next memory location! E.g. parr++ will result in 0x0180982 (+2). Pointer arithmetic includes the size of data type.

value = *parr;
Accessing the fifth element in the array:

parr += 5; value = *parr;
value = *(parr + 5) ;      // even shorter
Almost the same can be simulated in GFA-BASIC 32 using the Pointer-type. Except GFA-BASIC does not use the size of the data type into pointer arithmetic. A Pointer variable defines the type of the variable without an address, like C.

Local parr As Register Pointer Short
Pointer(parr) = 0x0180980
Local Short value 
value = parr

To obtain the value from the address GFA-BASIC 32 doesn't provide an indirection operator as C does, as in value = *parr. In GFA-BASIC 32 you must first assign the pointer variable an address using Pointer(parr)= addr. Once the pointer variable is assigned an address, it can be used as a normal variable. Note that Pointer()= performs an kind of implicit VarPtr(parr) = addr, because a pointer variables VarPtr == Null.
Incrementing the pointer to point to the next element requires to set the variable's VarPtr to the next address, in this case plus 2 (SizeOf(Short)==2). So, first give the variable a new address and than access the address using normal variable syntax.

Pointer(parr) = Pointer(parr) + SizeOf(parr)
value = parr

The next sample shows how to iterate over a C- array and how to access an element by index.

Dim C_str As String = "Hello"

' Iterating a C-array
Dim parr As Pointer Byte
Pointer(parr) = V:C_str
Trace Hex(Pointer(parr))
While parr <> 0
  Debug Chr(parr);
  Pointer(parr) = Pointer(parr) + SizeOf(parr)
Trace Hex(Pointer(parr))

' C-array using index
Pointer(parr) = V:C_str + 4 * SizeOf(parr)
Trace Chr(parr)

The code uses the Debug Window and shows the begin and ending address of the variable parr. The Debug commands show the byte (in character format) the parr Byte variable is addressing.