Must Pad Odd-Length Variables in COMMON Passed to MASM, C (70664)



The information in this article applies to:

  • Microsoft QuickBASIC 4.0
  • Microsoft QuickBASIC 4.0b
  • Microsoft QuickBASIC 4.5
  • Microsoft BASIC Compiler for MS-DOS and OS/2 6.0
  • Microsoft BASIC Compiler for MS-DOS and OS/2 6.0b
  • Microsoft Basic Professional Development System (PDS) for MS-DOS and MS OS/2 7.0
  • Microsoft Basic Professional Development System (PDS) for MS-DOS and MS OS/2 7.1
  • Microsoft Macro Assembler (MASM) 6.0
  • Microsoft Macro Assembler (MASM) 6.0a
  • Microsoft Macro Assembler (MASM) 6.0b
  • Microsoft Macro Assembler (MASM) 6.1

This article was previously published under Q70664

SUMMARY

Note that Basic automatically aligns each variable in COMMON on an even-byte boundary.

This means that when you pass odd-length fixed strings or odd-length user-defined TYPEs in a COMMON block from Basic to assembler or C, you must align the assembler or C structure variables that receive the COMMON onto even-byte boundaries. You must align variables correctly or their contents will be corrupted. You must always add padding for odd-length COMMON variables in assembler structures, but padding is necessary in C only if you compile the C code with the /Zp1 switch.

This information applies to Microsoft QuickBasic versions 4.00, 4.00b, and 4.50 for MS-DOS; to Microsoft Basic Compiler versions 6.00 and 6.00b for MS-DOS and MS OS/2; to Microsoft Basic Professional Development System (PDS) versions 7.00 and 7.10 for MS-DOS and MS OS/2; to all versions of the Microsoft Macro Assembler (MASM); and to supported versions of the Microsoft C Compiler.

MORE INFORMATION

Basic aligns all COMMON variables on even-byte boundaries for better data-addressing speed. This alignment affects assembler programmers more often than it affects C programmers.

Discussion for C

First, note that if any element (other than the last element) within a user-defined-TYPE variable passed to C has an odd length, then you must compile the C code with the /Zp1 option (to align C structures on byte boundaries instead of on word boundaries). /Zp1 is not necessary if just the last element within the user-defined TYPEs are odd.

If you compile the C code with /Zp1, then you must add 1 byte of padding in the C structure after each variable that has an odd overall length in Basic's COMMON. (Do not add padding between elements of a user-defined-TYPE variable or record; just add 1 byte of padding after the user-defined TYPE record if the record has an odd length.)

If /Zp1 is not required, and you compile the C code without /Zp1, then do not pad the C structure after odd-length COMMON variables, since they will be automatically word aligned.

For more information about calling C from Basic, query using the following word:

BAS2C

For more information about when /Zp1 is required when passing user-defined TYPEs from Basic to C, search for a separate article using the following words:

/Zp1 and odd and Basic

Discussion for MASM

In the assembly code, you must add a DB 1 DUP (?) statement after variables or user-defined-TYPE records in COMMON whose total length is odd.

The following assembler program demonstrates how odd-length variables should be padded to align with Basic's COMMON. The first variable in the COMMON is a user-defined TYPE with an overall length of 5 (no padding is allowed within a user-defined TYPE), so 1 byte of padding is added to the assembly language. The second variable is a fixed-length string of length 1. This is an odd length, so another byte of padding is needed. The last variable is an integer; since integers are stored in 2 bytes, no padding should be added.

If you are not sure how large is a variable of given TYPE, you can use the LEN function to return the length of that variable. For example, if you had
   DIM var AS SomeUserType
				
then LEN(var) returns the number of bytes in SomeUserType.

Note: The passing of Basic dynamic arrays within COMMON blocks to other languages is not supported. This would require knowledge of the format of the array descriptor, which is considered proprietary information. With static arrays, the entire array is put directly within the COMMON block.

For more information about calling assembler from Basic, query on the following word:

BAS2MASM

Compile and link the code (further below) as follows:
   BC BAS;
   MASM MASM;
   LINK BAS+MASM;
				
The Basic program will create four variables and store the following values values into them:
   aaa, bb, c, &H1111
				
The assembly language will then modify the variables to be:
   Xaa, Xb, X, &H1211
				

BAS.BAS

DECLARE SUB MasmProc ()
TYPE rectype
    a AS STRING * 3
    b AS STRING * 2
END TYPE
' Basic stores the following three variables contiguously in one
' COMMON named vars:
COMMON SHARED /vars/ typevar AS rectype
COMMON SHARED /vars/ stringvar AS STRING * 1
COMMON SHARED /vars/ intvar AS integer
typevar.a = "aaa": typevar.b = "bb": stringvar = "c": intvar = &H1111
CALL MasmProc
PRINT typevar.a: PRINT typevar.b: PRINT stringvar: PRINT hex$(intvar)
				

MASM.ASM

rectype STRUC
    a   db  3 dup (?)
    b   db  2 dup (?)
rectype ENDS

vars SEGMENT COMMON 'BC_VARS'
    typevar     rectype 1 dup (<>)
                db      1 dup (?)       ; pad typevar to word boundary
    stringvar   db      2 dup (?)
                db      1 dup (?)       ; more padding
    intvar      dw      1 dup (?)
vars ENDS

dgroup GROUP vars
.model medium, basic
.code
PUBLIC MasmProc
MasmProc    PROC
    push    bp                      ; preserve bp
    mov     typevar.a, 'X'              ; modify variables
    mov     typevar.b, 'X'
    mov     stringvar, 'X'
    inc     intvar
    pop     bp
    ret
MasmProc    ENDP
END
				

Modification Type:MinorLast Reviewed:8/16/2005
Keywords:KB70664