Struct

See Also: Declaring Variables: Array Declarations, Move, Struct Type, Struct Variables, Struct Declaration, Struct Variable Assignments, Struct Properties, SizeOfType

Purpose

Declares a new structured data type.

Syntax

Struct {type-name}

    {data-type} {member-name}

    [{data-type} {member-name}]

    […]

End_Struct

or

Struct {type-name}

    [ {Name={alternate-member-name} } ]

    {data-type} {member-name}

    [{data-type} {member-name}]

    […]

End_Struct

Where:

What It Does

A struct represents a set of elements where each element is called a member.  A struct type declaration defines a particular set of elements and associates it with a new type identifier.

Once a struct type is declared it can be used just like any other DataFlex data type. i.e. you may declare and use variables and properties, and you may declare procedure or function parameters and return types of a struct type. For example…

Struct tCreditCard    // declares a new struct type

    Integer iType

    String  sName

    Integer iNumber

    Date    dExpires

End_Struct

 

tCreditCard MyCreditCard  // declares a new variable of tCreditCard type

Members of a struct variable are accessed using the member access operator (the dot operator). For example…

Move 0                to MyCreditCard.iType

Move "Joe Bloggs"     to MyCreditCard.sName

Move 1234123412341234 to MyCreditCard.iNumber

 

Date dToday

Sysdate dToday

 

If (MyCreditCard.dExpires >= dToday) Showln "Expired!"

For each struct type defined, the compiler automatically defines the symbol _struct_{name} where {name} is replaced with the name of the struct type. This can be used at compile time to determine whether a particular struct type has been defined. For example:

#IFDEF _struct_tCreditCard

    // Do something special if the tCreditCard struct type has been defined

    ...

#ENDIF

For more information refer to struct types in the Language Guide.

Struct Alignment

Structure alignment (or structure padding) happens when structs are passed to other DLLs or Windows functions. This is because the compiler ensures that each struct instance will have the alignment of its widest scalar member (for performance reasons) and extra memory space may be inserted within the struct (unless structure alignment is explicitly switched off in the DLL).

DataFlex does not do structure alignment. This means that you might have to add extra padding items yourself to exposed Windows structs. This issue is especially relevant to the 64-bit platform. Take this example:

Struct tWinChooseFont

  DWord lStructSize

  Handle hwndOwner

End_Struct

In 32-bit, both DWord and Handle are 32-bit items (4 bytes), which does not lead to any padding. However, in 64-bit, Handle has become 64-bit (8 bytes) and that causes the struct to have 8-byte alignment, which means that in Windows compilers there will be 4 bytes of space inserted after lStructSize. If this doesn’t get corrected in 64-bit environments, there can be an unexpected runtime error or crash upon calling the external function. The solution in DataFlex code is:

Struct tWinChooseFont

  DWord lStructSize

#IFDEF IS$WIN64

  Integer iStructAlignment

#ENDIF

  Handle hwndOwner

End_Struct

Be aware that such changes might influence code where you do a SizeOfType() on that struct.

The structure alignment issue is not relevant to structs internal to your application (not passed to outside DLLs) or structs in COM class interfaces.

Examples

The following example demonstrates a nested struct declaration. i.e. a struct type with a member that is also a struct type.

Struct tAddress

    String Street

    String City

    String State

    Integer Zip

End_Struct

 

Struct tCompany

    String   Name

    tAddress PostalAddress

    tAddress Location

    Integer  Phone

End_Struct

The following example declares a struct variable named tStudent, then creates a dynamic array of type tStudent named myStudents. Next, a loop is created that finds Student records and fills the array with the information from the database.

// declare data type tStudent

Struct tStudent

    String FirstName

    String LastName

    String ClassName

    Integer LastTestScore

End_Struct

 

tStudent[] myStudents  // dynamic array of tStudent

 

open Student  // open Student table

 

integer i

for i from 0 to iNumberOfStudents

    clear Student

    move i to Student.Id

    find eq Student by 1  // Id

    if (Found) begin

        move Student.First     to myStudents[i].FirstName

        move Student.Last      to myStudents[i].LastName

        move Student.Class     to myStudents[i].ClassName

        move Student.TestScore to myStudents[i].LastTestScore

    end

loop

Example

Initializing struct variable members:

In the example below, move is used to initialize members of the myBillingAddress struct variable.

struct tUSAddress

    string sFirstName

    string sLastName

    string sAddressLine1

    string sAddressLine2

    string sCity

    string sState

    integer iZipCode

end_struct

 

Procedure CreateBillingAddress

    tUSAddress myBillingAddress

 

    // initialize myBillingAddress

    move "John"                  to myBillingAddress.sFirstName

    move "Smith"                 to myBillingAddress.sLastName

    move "Data Access Worldwide" to myBillingAddress.sAddressLine1

    move "14000 SW 119 Ave"      to myBillingAddress.sAddressLine2

    move "Miami"                 to myBillingAddress.sCity

    move "FL"                    to myBillingAddress.sState

    move "33186"                 to myBillingAddress.iZipCode

End_Procedure

Example

Copying struct variable members:

Assume that the example below is a continuation of the sample above, using the same struct declaration for tUSAddress. Here, move is used to copy the value of myBillingAddress to myShippingAddress. Using move to copy struct variables uses a deep memberwise copy operation to copy each struct variable member value from the first struct variable to the second struct variable.

Procedure CreateShippingAddress tUSAddress myBillingAddress

    tUSAddress myShippingAddress

 

    move myBillingAddress to myShippingAddress

End_Procedure

Re-initializing struct variable members:

There is a quick way to re-initialize array variables to their original (blank) values. Simply move an un-initialized array variable of the same type:

Struct tTest

    Integer iTest

    String sTest

End_Struct

 

Procedure Test

    tTest localTest blankTest

 

    // initialize localTest with values

    Move 104 to localTest.iTest

    Move "Fred" to localTest.sTest

 

    // re-initialize localTest elements to their original (blank) values

    Move blankTest to localTest

End_Procedure

The same can be done with struct properties:

Property tTest pMyTest

 

Procedure ReinitializepMyTest

    tTest blankTest

 

    Set pMyTest to blankTest

End_Procedure

Notes

Struct tContact

    String Company

    String[5] ContactNames

    Integer Fax

End_Struct

However the following declaration will produce a compile-time error.

Integer icNames

Move 5 to icNames

 

Struct tContact

    String Company

    String[icNames] ContactNames

    Integer Fax

End_Struct

This restriction does not apply to dynamic or jagged array struct members.