Arrays, Structures, Unions

Tibbo BASIC and Tibbo C support arrays and structures but the storage format in RAM differs between the two languages.

There is no compatibility: you cannot pass an array or a structure from a BASIC procedure to a C function, or vice versa.

There is no inherent limitation to the maximum number of array dimensions or the number of levels in a structure.

Unions are only supported in Tibbo C.

Arrays and structures in Tibbo BASIC

Like strings , arrays and structures in Tibbo BASIC contain 2-byte headers ensuring their safe handling.

Structures have multiple headers — one for each leaf of the structure's "tree".

Headers contain pointers to array and structure descriptors, which are compiled into the .TPC binary .

Owing to these headers, the VM is able to catch out-of-range access situations, thus preventing memory corruption (see ABORT(OOR) exception in Debugging ).

This makes Tibbo BASIC arrays and structures safe.

As in C, BASIC arrays count elements from 0 (not a useless note — some old BASIC implementation counted from 1).

Examples of array and structure definitions and use:

** Tibbo Basic **

sub on_sys_init
   dim x(5) as byte 'a byte array with 5 members

   dim s_array(5,2) as string(10) 'a two-dimensional array (5 "rows" of 2 "columns") of strings having a limited capacity of 10 bytes each

   type foo_struct 'structure with two members, and both are arrays  
      x(10) as byte
      s(10) as string(4)
   end type

   type bar_struct 'structure with two members, one if which is another structure
      foo as foo_struct
      w as word
   end type

   dim bar(3) as bar_struct 'an array of type "bar_struct"

   'then somewhere inside a function or a sub:
   dim f as byte
   for f=0 to f=4 'x has five members (0~4), and this is the "rightmost" one
      x(f)=f
   next f

   s_array(2,1)="Element 2,1"

   bar(1).foo.s(2)="test" 'woo-hoo! Addressing the element 2 of the member s of the member foo of element 1 of bar!
end sub 

Arrays, structures, and unions in Tibbo C

Arrays, structures, and unions of Tibbo C contain no special headers. They are implemented in the standard ANSI C way.

Therefore, they are not safe and your runaway program can easily cause out-of-range and memory corruption situations.

Do you want to know why we implemented C arrays, structures, and unions differently?

In C there is a close relationship between arrays and pointers. These two entities are very often interchangeable. Having extra headers would break this straightforward relationship.

Also, it is a common practice in C to process data by putting a structure over it. Say, you are processing network packets. The data format is defined by a structure. What do you normally do in C? You create a pointer of this structure's type, then point the pointer (with a cast) to a byte array. You can then work with the packet data "through" the structure. Well, if we had extra headers like in BASIC then the straightforward conversion between a block of binary data and structures would be impossible!

For this reason we implemented C arrays, structures, and unions in a 100% standard way. This preserves all the abilities of the C language. Regrettably, this also brings in all the "unsafeness" of C.  

The following C code example is impossible to implement in Tibbo BASIC. It parses two types of data packets — "PACKET_X" and "PACKET_Y".

This is a classical example of using unions and structures to look at the binary data.

In this case, this binary data is supposed to be prepared in the incoming_data[] array.

** Tibbo C **

#define PACKET_X 0x00
#define PACKET_Y 0x01

struct packet_x{
   unsigned char packet_type;
   unsigned int source_id;
   unsigned int dest_id;
   unsigned char payload_len;
};

struct packet_y{
   unsigned char packet_type;
   unsigned int source_id;
   unsigned char payload_len;
};

union packet{
   packet_x p_x;
   packet_y p_y;
};

unsigned char incoming_data[]; //this code example doesn't show how binary data gets into the array

...

void process_data(){
   unsigned int source_id,dest_id=0xFF;
   unsigned char payload_len;
   packet *packet_ptr=(packet *)&incoming_data;

   if(packet_ptr->p_x.packet_type==PACKET_X){
      source_id=packet_ptr->p_x.source_id;
      dest_id=packet_ptr->p_x.dest_id;
      payload_len=packet_ptr->p_x.payload_len;
   }
   else{
      source_id=packet_ptr->p_y.source_id;
      dest_id=0xFF;
      payload_len=packet_ptr->p_y.payload_len;
   }
}

Padding

Tibbo C compiles with the default #pragma pack value of (1). This means no padding for 8-bit and 16-bit members of C structures and unions.