KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q65924: How to Get Absolute Address of String Variable in BASIC

Article: Q65924
Product(s): See article
Version(s): 4.00 4.00b 4.50
Operating System(s): MS-DOS
Keyword(s): ENDUSER | SR# S900725-36 B_BasicCom | mspl13_basic
Last Modified: 19-OCT-1990

This article describes how to get the absolute memory address of the
contents of a variable-length string variable in compiled BASIC. The
sample code below also shows how to PEEK at the string in memory.

To get the physical (or absolute) address, you must multiply the
segment value (which is in paragraphs) by 16 bytes per paragraph, and
then add the offset value (which is in bytes). However, there are some
integer tricks necessary to work around the fact that the VARPTR,
VARSEG, SADD, and SSEG functions return a signed short integer instead
of an unsigned address, as described further below.

This information applies to 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; and to Microsoft BASIC Professional Development
System (PDS) versions 7.00 and 7.10 for MS-DOS and MS OS/2.

The above BASICs use a medium memory model. This means that a compiled
.EXE program (as well as a program being executed within the QB.EXE or
QBX.EXE environment) consists of multiple code segments and one data
segment (DGROUP). In the above BASICs, certain data items, such as
dynamic non-variable-length-string arrays, reside outside the near
data segment (DGROUP). In BASIC PDS 7.00 and 7.10, the contents of far
variable-length strings also reside outside DGROUP. Code and data
objects can thus be found in various places in memory, and the general
layout of these items is more complex than in earlier BASICs.

To determine the absolute address of any data item, you first must
obtain the segment and offset of that data item.

The VARSEG function returns the segment of any variable or near string
descriptor. However, in BASIC PDS 7.00 and 7.10, you must use the SSEG
function (instead of VARSEG) to find the segment for the contents of
far strings because VARSEG is useless for far strings. VARSEG just
finds the segment of the descriptor for near strings in BASIC PDS 7.00
and 7.10. SSEG can be used to find the segment of the contents of both
near and far strings in BASIC PDS 7.00 and 7.10.

The offset can be found with the SADD function (for the contents of
variable-length strings) or the VARPTR function for all other data
types (including fixed-length strings).

The segment value is measured in paragraphs, whereas the offset is
measured in bytes. You must multiply the segment value by 16 bytes per
paragraph to convert to bytes. (Segments are numbered on paragraph
boundaries, which are every 16 bytes.)

To get the physical (or absolute) address, you must multiply the
segment value by 16 decimals (10 Hex) and then add the offset value.

Special Integer Handling Is Required for Addresses Above 32767
--------------------------------------------------------------

The VARPTR, VARSEG, SADD, and SSEG functions return values anywhere
between 0 (zero) and FFFF hex (or between 0 and 65535 in unsigned
decimal notation).

However, if VARPTR, VARSEG, SADD, or SSEG return an address value
between 8000 hex and FFFF hex (or between 32768 and 65535 in unsigned
decimal notation), which you may assign to a short or long integer,
then BASIC reports the integer as negative (from -32768 to -1,
respectively). This occurs because the VARPTR, VARSEG, SADD, and SSEG
functions return a signed short integer. BASIC does not have an
unsigned data type. This means that if the integer variable returned
(from VARPTR, VARSEG, SADD, or SSEG) is negative, you must convert it
to its equivalent unsigned value and assign to a long integer. (A long
integer can store positive numbers between 32768 and 65535, unlike a
short integer.) The Unsigned& FUNCTION below is provided for this
purpose.

For more information about converting a BASIC signed integer to
unsigned and assigning to a long integer, search for a separate
article using following words:

   how AND convert AND BASIC AND unsigned AND integer

Code Example of Calculating Absolute Address of String Contents
---------------------------------------------------------------

This program determines the absolute address of the contents of a
variable-length string in memory. The program also uses the PEEK
function and prints the string byte by byte. To make the program work
in BASIC PDS 7.00 or 7.10 when using BC /Fs (far strings) or running
in QBX.EXE, you must use SSEG instead of VARSEG, as shown (or else the
wrong address will be used and PEEK will return random characters).

DECLARE FUNCTION Unsigned& (param%)
CLS
strng$ = "Quigzy Sticks are gurus"  ' initialize variable
offset% = SADD(strng$)    ' Get VARPTR value, assign to short integer
' Use only one of the following segment% assignments, depending upon
' which BASIC version you have:
segment% = VARSEG(strng$)  ' Get VARSEG value, assign to short integer
                           ' in QuickBASIC 4.x, BASIC compiler 6.00x.
                           ' In BASIC PDS 7.00/7.10, VARSEG only gives
                           ' segment for near string descriptors;
                           ' VARSEG is useless for far strings.
'segment% = SSEG(strng$)  ' Get SSEG value, assign to short integer
                          ' in BASIC PDS 7.00/7.10 if using BC /Fs
                          ' (far strings) or running in QBX.EXE.
                          ' SSEG works with far or near strings.
' Convert short integer offset% to unsigned long integer loffset& :
loffset& = Unsigned&(offset%)
' Convert short integer segment% to unsigned long integer lsegment& :
lsegment& = Unsigned&(segment%)
lsegment& = lsegment& * 16  ' Convert segment paragraphs to bytes.
address& = lsegment& + loffset&   ' Calculate absolute address.
DEF SEG = segment%
FOR i = 0 TO (LEN(strng$) - 1)
  a = PEEK(loffset& + i)          'Print out the string byte by byte.
  PRINT CHR$(a);
NEXT
PRINT : PRINT
PRINT "The above string is located at the following RAM location:"
PRINT "Absolute machine address in decimal : "; address&
PRINT "Absolute machine address in hex     :  "; HEX$(address&)

FUNCTION Unsigned& (param%)
' This function returns the unsigned long integer form of the
' short integer param%, which was passed as input.
   IF param% < 0 THEN
      Unsigned& = &HFFFF& AND param%
   ELSE
      Unsigned& = param%
   END IF
END FUNCTION

Manual Example of Calculating Absolute Address in Hex Notation
--------------------------------------------------------------

Multiplying by 16 corresponds to shifting the segment value 4 bits to
the left in binary notation (2 ^ 4 = 16), or in hex notation, shifting
the segment value to the left by one hex digit. The easiest way
manually to multiply by 16 is to work with segment values in Hex and
append a zero to the right side of the Hex value.

For example, assume the segment value is &h1234 and the offset value
is &h4321. To add the segment and offset together and calculate the
absolute address, you must first multiply the segment by &h10, as
follows:

   &h1234 times &h10 equals &h12340

&h12340 is thus the absolute byte location of the segment. Now, add
the offset to the absolute byte location of the segment, as follows:

   &h12340 plus &h4321 equals &h13661

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.