Copyright: Copyright 1996 Sybase, Inc. and its subsidiaries. All rights reserved.   Tuesday, May 25, 2010 09:39:05


Index of Topics

- " -

The "/fh[q]" (Precompiled Header) Option

- 0 -

0

- 1 -

1

16-bit Assembly Language Considerations

16-bit Code Models

16-bit Data Models

16-bit Memory Layout

16-bit Memory Models

16-bit Pragmas

16-bit:  A Function that Never Returns

16-bit:  Alias Names

16-bit:  Alternate Names for Symbols

16-bit:  An Example

16-bit:  Auxiliary Pragmas

16-bit:  Auxiliary Pragmas and the 80x87

16-bit:  Calling Conventions for 80x87-based Applications

16-bit:  Calling Conventions for Non-80x87 Applications

16-bit:  Data Representation

16-bit:  Defining Exported Symbols in Dynamic Link Libraries

16-bit:  Defining Windows Callback Functions

16-bit:  Describing Argument Information

16-bit:  Describing Calling Information

16-bit:  Describing Function Return Information

16-bit:  Describing How Functions Use Memory

16-bit:  Describing the Registers Modified by a Function

16-bit:  Effect of Function Prototypes on Arguments

16-bit:  Forcing a Stack Frame

16-bit:  Forcing Arguments into Specific Registers

16-bit:  Functions with Variable Number of Arguments

16-bit:  Interfacing to Assembly Language Functions

16-bit:  Loading Data Segment Register

16-bit:  Memory Layout

16-bit:  Passing Arguments in Registers

16-bit:  Passing Arguments in Reverse Order

16-bit:  Passing Arguments to In-Line Functions

16-bit:  Passing Arguments Using Register-Based Calling Conventions

16-bit:  Passing Values in 80x87-based Applications

16-bit:  Predefined "__cdecl" Alias

16-bit:  Predefined "__pascal" Alias

16-bit:  Predefined "__watcall" Alias

16-bit:  Predefined Aliases

16-bit:  Preserving 80x87 Floating-Point Registers Across Calls

16-bit:  Removing Arguments from the Stack

16-bit:  Returning Floating-Point Data

16-bit:  Returning Function Values in Registers

16-bit:  Returning Structures

16-bit:  Returning Values from Functions

16-bit:  Returning Values in 80x87-based Applications

16-bit:  Setting Priority of Static Data Initialization (C++ Only)

16-bit:  Size of Enumerated Types

16-bit:  Sizes of Predefined Types

16-bit:  Specifying Symbol Attributes

16-bit:  The ALIAS Pragma (C Only)

16-bit:  The ALLOC_TEXT Pragma (C Only)

16-bit:  The CODE_SEG Pragma

16-bit:  The COMMENT Pragma

16-bit:  The DATA_SEG Pragma

16-bit:  The DISABLE_MESSAGE Pragma

16-bit:  The DUMP_OBJECT_MODEL Pragma (C++ Only)

16-bit:  The ENABLE_MESSAGE Pragma

16-bit:  The ENUM Pragma

16-bit:  The ERROR Pragma

16-bit:  The EXTREF Pragma

16-bit:  The FUNCTION Pragma

16-bit:  The INCLUDE_ALIAS Pragma

16-bit:  The INLINE_DEPTH Pragma (C++ Only)

16-bit:  The INLINE_RECURSION Pragma (C++ Only)

16-bit:  The INTRINSIC Pragma

16-bit:  The MESSAGE Pragma

16-bit:  The ONCE Pragma

16-bit:  The PACK Pragma

16-bit:  The READ_ONLY_FILE Pragma

16-bit:  The TEMPLATE_DEPTH Pragma (C++ Only)

16-bit:  The WARNING Pragma (C++ Only)

16-bit:  Type "char"

16-bit:  Type "double"

16-bit:  Type "float"

16-bit:  Type "int"

16-bit:  Type "long int"

16-bit:  Type "short int"

16-bit:  Using Pragmas to Specify Default Libraries

16-bit:  Using Pragmas to Specify Options

16-bit:  Using the 80x87 to Pass Arguments

16-bit:  Using the 80x87 to Return Function Values

- 2 -

2

- 3 -

3

32-bit Assembly Language Considerations

32-bit Code Models

32-bit Data Models

32-bit Memory Layout

32-bit Memory Models

32-bit Pragmas

32-bit:  A Function that Never Returns

32-bit:  Alias Names

32-bit:  Alternate Names for Symbols

32-bit:  An Example

32-bit:  Auxiliary Pragmas

32-bit:  Auxiliary Pragmas and the 80x87

32-bit:  Calling Conventions for 80x87-based Applications

32-bit:  Calling Conventions for Non-80x87 Applications

32-bit:  Data Representation

32-bit:  Defining Exported Symbols in Dynamic Link Libraries

32-bit:  Describing Argument Information

32-bit:  Describing Calling Information

32-bit:  Describing Function Return Information

32-bit:  Describing How Functions Use Memory

32-bit:  Describing the Registers Modified by a Function

32-bit:  Effect of Function Prototypes on Arguments

32-bit:  Forcing a Stack Frame

32-bit:  Forcing Arguments into Specific Registers

32-bit:  Functions with Variable Number of Arguments

32-bit:  Interfacing to Assembly Language Functions

32-bit:  Loading Data Segment Register

32-bit:  Memory Layout

32-bit:  Passing Arguments in Registers

32-bit:  Passing Arguments in Reverse Order

32-bit:  Passing Arguments to In-Line Functions

32-bit:  Passing Arguments Using Register-Based Calling Conventions

32-bit:  Passing Values in 80x87-based Applications

32-bit:  Predefined "__cdecl" Alias

32-bit:  Predefined "__pascal" Alias

32-bit:  Predefined "__stdcall" Alias

32-bit:  Predefined "__syscall" Alias

32-bit:  Predefined "__watcall" Alias (register calling convention)

32-bit:  Predefined "__watcall" Alias (stack calling convention)

32-bit:  Predefined Aliases

32-bit:  Preserving 80x87 Floating-Point Registers Across Calls

32-bit:  Removing Arguments from the Stack

32-bit:  Returning Floating-Point Data

32-bit:  Returning Function Values in Registers

32-bit:  Returning Structures

32-bit:  Returning Values from Functions

32-bit:  Returning Values in 80x87-based Applications

32-bit:  Setting Priority of Static Data Initialization (C++ Only)

32-bit:  Size of Enumerated Types

32-bit:  Sizes of Predefined Types

32-bit:  Specifying Symbol Attributes

32-bit:  The ALIAS Pragma (C Only)

32-bit:  The ALLOC_TEXT Pragma (C Only)

32-bit:  The CODE_SEG Pragma

32-bit:  The COMMENT Pragma

32-bit:  The DATA_SEG Pragma

32-bit:  The DISABLE_MESSAGE Pragma

32-bit:  The DUMP_OBJECT_MODEL Pragma (C++ Only)

32-bit:  The ENABLE_MESSAGE Pragma

32-bit:  The ENUM Pragma

32-bit:  The ERROR Pragma

32-bit:  The EXTREF Pragma

32-bit:  The FUNCTION Pragma

32-bit:  The INCLUDE_ALIAS Pragma

32-bit:  The INLINE_DEPTH Pragma (C++ Only)

32-bit:  The INLINE_RECURSION Pragma (C++ Only)

32-bit:  The INTRINSIC Pragma

32-bit:  The MESSAGE Pragma

32-bit:  The ONCE Pragma

32-bit:  The PACK Pragma

32-bit:  The READ_ONLY_FILE Pragma

32-bit:  The TEMPLATE_DEPTH Pragma (C++ Only)

32-bit:  The WARNING Pragma (C++ Only)

32-bit:  Type "char"

32-bit:  Type "double"

32-bit:  Type "float"

32-bit:  Type "int"

32-bit:  Type "long int"

32-bit:  Type "short int"

32-bit:  Using Pragmas to Specify Default Libraries

32-bit:  Using Pragmas to Specify Options

32-bit:  Using Stack-Based Calling Conventions

32-bit:  Using the 80x87 to Pass Arguments

32-bit:  Using the 80x87 to Return Function Values

3{r|s}

- 4 -

4

4{r|s}

- 5 -

5

5{r|s}

- 6 -

6

6{r|s}

- 8 -

80x86 Floating Point

80x86 Run-time Conventions

- _ -

The __declspec Keyword

- A -

About This Manual

ad[=<file_name>]

adbs

add[=<file_name>]

adfs

adhp[=<path_name>]

adt[=<target_name>]

- B -

Based Pointers

bc

bd

Benchmarking Hints

bg

bm

br

bt[=<os>]

bw

- C -

C++ Exception Handling

Choosing the Correct Floating-Point Option

Code Generation

Compatibility with Microsoft Visual C++

Compatibility with Older Versions of the 80x86 Compilers

Compiler Diagnostics

Compiler Options - Full Description

Compiler Options - Indexed

Compiler Options - Summarized Alphabetically

Compiler Options - Summarized By Category

Consistency Rules for Precompiled Headers

Creating a Tiny Memory Model Application

Creating and Using Precompiled Headers

Creating ROM-based Applications

- D -

d+

d0

d1

d1+

d2

d2i

d2s

d2t

d3

d3i

d3s

d<name>[=text]

db

Debugging/Profiling

Diagnostics

Double-Byte/Unicode Characters

- E -

e<number>

ecc

ecd

ecf

ecp

ecr

ecs

ecw

ee

ef

ei

em

en

Environment Variables

ep[<number>]

eq

er

errno Values and Their Meanings

et

ew

Exception Filters and Exception Handlers

ez

- F -

fc=<file_name>

fh[q][=<file_name>]

fhd

fhr

fhw

fhwe

fi=<file_name>

Flat Memory Model

fo[=<file_name>]

fo[=<file_name>] (preprocessor)

FORCE

fp2

fp3

fp5

fp6

fpc

fpd

fpi

fpi87

fpr

fr[=<file_name>]

ft

fti

fx

fzh

fzs

- G -

g=<codegroup>

- H -

h{w,d,c}

- I -

i=<directory>

In-line Assembly Directives and Opcodes

In-line Assembly Language

In-line Assembly Language Default Environment

In-line Assembly Language Tutorial

In-line Assembly Language using _asm

INCLUDE

- J -

j

- K -

k

- L -

Labels in In-line Assembly Code

LFN

The LFN Environment Variable

LIB

LIBDOS

LIBOS2

LIBPHAR

LIBWIN

Linking Applications for the Various 16-bit Memory Models

Linking Applications for the Various 32-bit Memory Models

- M -

Math Run-Time Error Messages

mc

mf

mh

Mixed 16-bit Memory Model

Mixed 32-bit Memory Model

Mixing and Matching _try/_finally and _try/_except

ml

mm

Modifying the Startup Code

ms

- N -

nc=<name>

nd=<name>

nm=<name>

NO87

The NO87 Environment Variable

nt=<name>

- O -

oa

ob

oc

od

oe=<num>

of

of+

oh

oi

oi+

ok

ol

ol+

om

on

oo

op

Open Watcom C/C++ #include File Processing

Open Watcom C/C++ 80x87 Math Libraries

Open Watcom C/C++ Alternate Math Libraries

Open Watcom C/C++ C Libraries

Open Watcom C/C++ Class Libraries

Open Watcom C/C++ Command Line Examples

Open Watcom C/C++ Command Line Format

Open Watcom C/C++ Compiler Options

The Open Watcom C/C++ Compilers

Open Watcom C/C++ DLL-based Compilers

Open Watcom C/C++ Extended Keywords

The Open Watcom C/C++ Libraries

Open Watcom C/C++ Library Directory Structure

Open Watcom C/C++ Math Libraries

Open Watcom C/C++ Predefined Macros

Open Watcom C/C++ Preprocessor

The Open Watcom C/C++ Run-time Initialization Routines

Open Watcom C/C++ Run-Time Messages

The Open Watcom Code Generator

Optimizations

or

os

ot

ou

ox

oz

- P -

PATH

pil

Precompiled Headers

Preprocessor

p{e,l,c,w=<num>}

- Q -

q

- R -

r

Refining Exception Handling

Resuming Execution After an Exception

ri

ROMable Functions

Run-Time Error Messages

- S -

s

Segment Constant Based Pointers and Objects

Segment Object Based Pointers

Segments/Modules

Self Based Pointers

sg

Source/Output Control

st

Structured Exception Handling

Summary of 16-bit Memory Models

Summary of 32-bit Memory Models

Summary:  80x86 Floating Point

Summary:  80x86 Run-time Conventions

Summary:  C++ Exception Handling

Summary:  Code Generation

Summary:  Compatibility with Microsoft Visual C++

Summary:  Compatibility with Older Versions of the 80x86 Compilers

Summary:  Debugging/Profiling

Summary:  Diagnostics

Summary:  Double-Byte/Unicode Characters

Summary:  Optimizations

Summary:  Preprocessor

Summary:  Segments/Modules

Summary:  Source/Output Control

Summary:  Target Specific

System-Dependent Functions

- T -

t=<num>

Target Specific

Termination Handlers

Throwing Your Own Exceptions

Tiny Memory Model

TMP

- U -

u<name>

Use of Environment Variables

- V -

v

Variables in In-line Assembly Code

vc...

vcap

Void Based Pointers

- W -

w<number>

WATCOM

WCC

WCC386

wcd=<number>

wce=<number>

WCGMEMORY

WCL

WCL386

WD

WDW

we

When to Precompile Header Files

WLANG

wo

WPP

WPP386

wx

- X -

xd

xds

xdt

xr

xs

xss

xst

- Z -

za

zat

zc

zdl

zd{f,p}

ze

zev

zf

zfw

zf{f,p}

zg

zg{f,p}

zk0u

zku=<codepage>

zk{0,1,2,l}

zl

zld

zlf

zls

zm

zmf

zp[{1,2,4,8,16}]

zpw

zq

zri

zro

zs

zt<number>

zu

zv

zw

zW (optimized)

zWs

zz


Table of Contents

About This Manual

Open Watcom C/C++ Compiler Options

Compiler Options - Indexed

Compiler Options - Summarized Alphabetically

Compiler Options - Summarized By Category

Summary:  Target Specific

Summary:  Debugging/Profiling

Summary:  Preprocessor

Summary:  Diagnostics

Summary:  Source/Output Control

Summary:  Code Generation

Summary:  80x86 Floating Point

Summary:  Segments/Modules

Summary:  80x86 Run-time Conventions

Summary:  Optimizations

Summary:  C++ Exception Handling

Summary:  Double-Byte/Unicode Characters

Summary:  Compatibility with Microsoft Visual C++

Summary:  Compatibility with Older Versions of the 80x86 Compilers

Compiler Options - Full Description

Target Specific

bc

bd

bg

bm

br

bt[=<os>]

bw

of

of+

sg

st

zw

zW (optimized)

zWs

Debugging/Profiling

d0

d1

d1+

d2

d2i

d2s

d2t

d3

d3i

d3s

ee

en

ep[<number>]

et

h{w,d,c}

s

Preprocessor

d<name>[=text]

d+

fo[=<file_name>] (preprocessor)

pil

p{e,l,c,w=<num>}

u<name>

Diagnostics

e<number>

ef

eq

er

ew

q

t=<num>

w<number>

wcd=<number>

wce=<number>

we

wo

wx

za

ze

zq

zs

Source/Output Control

ad[=<file_name>]

adbs

add[=<file_name>]

adhp[=<path_name>]

adfs

adt[=<target_name>]

db

ez

fc=<file_name>

fh[q][=<file_name>]

fhd

fhr

fhw

fhwe

fi=<file_name>

fo[=<file_name>]

fr[=<file_name>]

ft

fti

fx

fzh

fzs

i=<directory>

k

v

zat

zf

zg

zl

zld

zlf

zls

Code Generation

ecc

ecd

ecf

ecp

ecr

ecs

ecw

ei

em

j

ri

xr

zc

zp[{1,2,4,8,16}]

zpw

zt<number>

zv

80x86 Floating Point

fpc

fpi

fpi87

fp2

fp3

fp5

fp6

fpd

Segments/Modules

g=<codegroup>

nc=<name>

nd=<name>

nm=<name>

nt=<name>

zm

zmf

80x86 Run-time Conventions

0

1

2

3

4

5

6

3{r|s}

4{r|s}

5{r|s}

6{r|s}

mf

ms

mm

mc

ml

mh

zd{f,p}

zdl

zev

zf{f,p}

zfw

zg{f,p}

zri

zro

zu

Optimizations

oa

ob

oc

od

oe=<num>

oh

oi

oi+

ok

ol

ol+

om

on

oo

op

or

os

ot

ou

ox

oz

C++ Exception Handling

xd

xdt

xds

xs

xst

xss

Double-Byte/Unicode Characters

zk{0,1,2,l}

zk0u

zku=<codepage>

Compatibility with Microsoft Visual C++

vc...

vcap

Compatibility with Older Versions of the 80x86 Compilers

r

fpr

zz

The Open Watcom C/C++ Compilers

Open Watcom C/C++ Command Line Format

Open Watcom C/C++ DLL-based Compilers

Environment Variables

Open Watcom C/C++ Command Line Examples

Benchmarking Hints

Compiler Diagnostics

Open Watcom C/C++ #include File Processing

Open Watcom C/C++ Preprocessor

Open Watcom C/C++ Predefined Macros

Open Watcom C/C++ Extended Keywords

Based Pointers

Segment Constant Based Pointers and Objects

Segment Object Based Pointers

Void Based Pointers

Self Based Pointers

The __declspec Keyword

The Open Watcom Code Generator

Precompiled Headers

When to Precompile Header Files

Creating and Using Precompiled Headers

The "/fh[q]" (Precompiled Header) Option

Consistency Rules for Precompiled Headers

The Open Watcom C/C++ Libraries

Open Watcom C/C++ Library Directory Structure

Open Watcom C/C++ C Libraries

Open Watcom C/C++ Class Libraries

Open Watcom C/C++ Math Libraries

Open Watcom C/C++ 80x87 Math Libraries

Open Watcom C/C++ Alternate Math Libraries

The NO87 Environment Variable

The LFN Environment Variable

The Open Watcom C/C++ Run-time Initialization Routines

16-bit Memory Models

16-bit Code Models

16-bit Data Models

Summary of 16-bit Memory Models

Tiny Memory Model

Mixed 16-bit Memory Model

Linking Applications for the Various 16-bit Memory Models

Creating a Tiny Memory Model Application

16-bit Memory Layout

16-bit Assembly Language Considerations

16-bit:  Data Representation

16-bit:  Type "char"

16-bit:  Type "short int"

16-bit:  Type "long int"

16-bit:  Type "int"

16-bit:  Type "float"

16-bit:  Type "double"

16-bit:  Memory Layout

16-bit:  Calling Conventions for Non-80x87 Applications

16-bit:  Passing Arguments Using Register-Based Calling Conventions

16-bit:  Sizes of Predefined Types

16-bit:  Size of Enumerated Types

16-bit:  Effect of Function Prototypes on Arguments

16-bit:  Interfacing to Assembly Language Functions

16-bit:  Functions with Variable Number of Arguments

16-bit:  Returning Values from Functions

16-bit:  Calling Conventions for 80x87-based Applications

16-bit:  Passing Values in 80x87-based Applications

16-bit:  Returning Values in 80x87-based Applications

16-bit Pragmas

16-bit:  Using Pragmas to Specify Options

16-bit:  Using Pragmas to Specify Default Libraries

16-bit:  The ALIAS Pragma (C Only)

16-bit:  The ALLOC_TEXT Pragma (C Only)

16-bit:  The CODE_SEG Pragma

16-bit:  The COMMENT Pragma

16-bit:  The DATA_SEG Pragma

16-bit:  The DISABLE_MESSAGE Pragma

16-bit:  The DUMP_OBJECT_MODEL Pragma (C++ Only)

16-bit:  The ENABLE_MESSAGE Pragma

16-bit:  The ENUM Pragma

16-bit:  The ERROR Pragma

16-bit:  The EXTREF Pragma

16-bit:  The FUNCTION Pragma

16-bit:  The INCLUDE_ALIAS Pragma

16-bit:  Setting Priority of Static Data Initialization (C++ Only)

16-bit:  The INLINE_DEPTH Pragma (C++ Only)

16-bit:  The INLINE_RECURSION Pragma (C++ Only)

16-bit:  The INTRINSIC Pragma

16-bit:  The MESSAGE Pragma

16-bit:  The ONCE Pragma

16-bit:  The PACK Pragma

16-bit:  The READ_ONLY_FILE Pragma

16-bit:  The TEMPLATE_DEPTH Pragma (C++ Only)

16-bit:  The WARNING Pragma (C++ Only)

16-bit:  Auxiliary Pragmas

16-bit:  Specifying Symbol Attributes

16-bit:  Alias Names

16-bit:  Predefined Aliases

16-bit:  Predefined "__cdecl" Alias

16-bit:  Predefined "__pascal" Alias

16-bit:  Predefined "__watcall" Alias

16-bit:  Alternate Names for Symbols

16-bit:  Describing Calling Information

16-bit:  Loading Data Segment Register

16-bit:  Defining Exported Symbols in Dynamic Link Libraries

16-bit:  Defining Windows Callback Functions

16-bit:  Forcing a Stack Frame

16-bit:  Describing Argument Information

16-bit:  Passing Arguments in Registers

16-bit:  Forcing Arguments into Specific Registers

16-bit:  Passing Arguments to In-Line Functions

16-bit:  Removing Arguments from the Stack

16-bit:  Passing Arguments in Reverse Order

16-bit:  Describing Function Return Information

16-bit:  Returning Function Values in Registers

16-bit:  Returning Structures

16-bit:  Returning Floating-Point Data

16-bit:  A Function that Never Returns

16-bit:  Describing How Functions Use Memory

16-bit:  Describing the Registers Modified by a Function

16-bit:  An Example

16-bit:  Auxiliary Pragmas and the 80x87

16-bit:  Using the 80x87 to Pass Arguments

16-bit:  Using the 80x87 to Return Function Values

16-bit:  Preserving 80x87 Floating-Point Registers Across Calls

32-bit Memory Models

32-bit Code Models

32-bit Data Models

Summary of 32-bit Memory Models

Flat Memory Model

Mixed 32-bit Memory Model

Linking Applications for the Various 32-bit Memory Models

32-bit Memory Layout

32-bit Assembly Language Considerations

32-bit:  Data Representation

32-bit:  Type "char"

32-bit:  Type "short int"

32-bit:  Type "long int"

32-bit:  Type "int"

32-bit:  Type "float"

32-bit:  Type "double"

32-bit:  Memory Layout

32-bit:  Calling Conventions for Non-80x87 Applications

32-bit:  Passing Arguments Using Register-Based Calling Conventions

32-bit:  Sizes of Predefined Types

32-bit:  Size of Enumerated Types

32-bit:  Effect of Function Prototypes on Arguments

32-bit:  Interfacing to Assembly Language Functions

32-bit:  Using Stack-Based Calling Conventions

32-bit:  Functions with Variable Number of Arguments

32-bit:  Returning Values from Functions

32-bit:  Calling Conventions for 80x87-based Applications

32-bit:  Passing Values in 80x87-based Applications

32-bit:  Returning Values in 80x87-based Applications

32-bit Pragmas

32-bit:  Using Pragmas to Specify Options

32-bit:  Using Pragmas to Specify Default Libraries

32-bit:  The ALIAS Pragma (C Only)

32-bit:  The ALLOC_TEXT Pragma (C Only)

32-bit:  The CODE_SEG Pragma

32-bit:  The COMMENT Pragma

32-bit:  The DATA_SEG Pragma

32-bit:  The DISABLE_MESSAGE Pragma

32-bit:  The DUMP_OBJECT_MODEL Pragma (C++ Only)

32-bit:  The ENABLE_MESSAGE Pragma

32-bit:  The ENUM Pragma

32-bit:  The ERROR Pragma

32-bit:  The EXTREF Pragma

32-bit:  The FUNCTION Pragma

32-bit:  The INCLUDE_ALIAS Pragma

32-bit:  Setting Priority of Static Data Initialization (C++ Only)

32-bit:  The INLINE_DEPTH Pragma (C++ Only)

32-bit:  The INLINE_RECURSION Pragma (C++ Only)

32-bit:  The INTRINSIC Pragma

32-bit:  The MESSAGE Pragma

32-bit:  The ONCE Pragma

32-bit:  The PACK Pragma

32-bit:  The READ_ONLY_FILE Pragma

32-bit:  The TEMPLATE_DEPTH Pragma (C++ Only)

32-bit:  The WARNING Pragma (C++ Only)

32-bit:  Auxiliary Pragmas

32-bit:  Specifying Symbol Attributes

32-bit:  Alias Names

32-bit:  Predefined Aliases

32-bit:  Predefined "__cdecl" Alias

32-bit:  Predefined "__pascal" Alias

32-bit:  Predefined "__stdcall" Alias

32-bit:  Predefined "__syscall" Alias

32-bit:  Predefined "__watcall" Alias (register calling convention)

32-bit:  Predefined "__watcall" Alias (stack calling convention)

32-bit:  Alternate Names for Symbols

32-bit:  Describing Calling Information

32-bit:  Loading Data Segment Register

32-bit:  Defining Exported Symbols in Dynamic Link Libraries

32-bit:  Forcing a Stack Frame

32-bit:  Describing Argument Information

32-bit:  Passing Arguments in Registers

32-bit:  Forcing Arguments into Specific Registers

32-bit:  Passing Arguments to In-Line Functions

32-bit:  Removing Arguments from the Stack

32-bit:  Passing Arguments in Reverse Order

32-bit:  Describing Function Return Information

32-bit:  Returning Function Values in Registers

32-bit:  Returning Structures

32-bit:  Returning Floating-Point Data

32-bit:  A Function that Never Returns

32-bit:  Describing How Functions Use Memory

32-bit:  Describing the Registers Modified by a Function

32-bit:  An Example

32-bit:  Auxiliary Pragmas and the 80x87

32-bit:  Using the 80x87 to Pass Arguments

32-bit:  Using the 80x87 to Return Function Values

32-bit:  Preserving 80x87 Floating-Point Registers Across Calls

In-line Assembly Language

In-line Assembly Language Default Environment

In-line Assembly Language Tutorial

Labels in In-line Assembly Code

Variables in In-line Assembly Code

In-line Assembly Language using _asm

In-line Assembly Directives and Opcodes

Structured Exception Handling

Termination Handlers

Exception Filters and Exception Handlers

Resuming Execution After an Exception

Mixing and Matching _try/_finally and _try/_except

Refining Exception Handling

Throwing Your Own Exceptions

Creating ROM-based Applications

ROMable Functions

System-Dependent Functions

Modifying the Startup Code

Choosing the Correct Floating-Point Option

Use of Environment Variables

FORCE

INCLUDE

LFN

LIB

LIBDOS

LIBWIN

LIBOS2

LIBPHAR

NO87

PATH

TMP

WATCOM

WCC

WCC386

WCL

WCL386

WCGMEMORY

WD

WDW

WLANG

WPP

WPP386

Open Watcom C/C++ Run-Time Messages

Run-Time Error Messages

errno Values and Their Meanings

Math Run-Time Error Messages


About This Manual

This manual contains the following chapters:

Chapter 1 -

About This Manual.

This chapter provides an overview of the contents of this guide.

Chapter 2 -

Open Watcom C/C++ Compiler Options.

This chapter provides a summary and reference section for all the C and C++ compiler options.

Chapter 3 -

The Open Watcom C/C++ Compilers.

This chapter describes how to compile an application from the command line.  This chapter also describes compiler environment variables, benchmarking hints, compiler diagnostics, #include file processing, the preprocessor, predefined macros, extended keywords, and the code generator.

Chapter 4 -

Precompiled Headers.

This chapter describes the use of precompiled headers to speed up compilation.

Chapter 5 -

The Open Watcom C/C++ Libraries.

This chapter describes the Open Watcom C/C++ library directory structure, C libraries, class libraries, math libraries, 80x87 math libraries, alternate math libraries, the "NO87" environment variable, and the run-time initialization routines.

Chapter 6 -

16-bit Memory Models.

This chapter describes the Open Watcom C/C++ memory models (including code and data models), the tiny memory model, the mixed memory model, linking applications for the various memory models, creating a tiny memory model application, and memory layout in an executable.

Chapter 7 -

16-bit Assembly Language Considerations.

This chapter describes issues relating to 16-bit interfacing such as parameter passing conventions.

Chapter 8 -

16-bit Pragmas.

This chapter describes the use of pragmas with the 16-bit compilers.

Chapter 9 -

32-bit Memory Models.

This chapter describes the Open Watcom C/C++ memory models (including code and data models), the flat memory model, the mixed memory model, linking applications for the various memory models, and memory layout in an executable.

Chapter 10 -

32-bit Assembly Language Considerations.

This chapter describes issues relating to 32-bit interfacing such as parameter passing conventions.

Chapter 11 -

32-bit Pragmas.

This chapter describes the use of pragmas with the 32-bit compilers.

Chapter 12 -

In-line Assembly Language.

This chapter describes in-line assembly language programming using the auxiliary pragma.

Chapter 13 -

Creating ROM-based Applications.

This chapter discusses some embedded systems issues as they pertain to the C library.

Appendix A.  -

Use of Environment Variables.

This appendix describes all the environment variables used by the compilers and related tools.

Appendix B.  -

Open Watcom C/C++ Run-Time Messages.

This appendix lists all of the C/C++ run-time diagnostic messages with an explanation for each.


Open Watcom C/C++ Compiler Options

Source files can be compiled using either the IDE or command-line compilers.  This chapter describes all the compiler options that are available.

For information about compiling applications from the IDE, see the Open Watcom Graphical Tools User's Guide.

For information about compiling applications from the command line, see the chapter entitled The Open Watcom C/C++ Compilers.

The Open Watcom C/C++ compiler command names (compiler_name) are:

WCC

the Open Watcom C compiler for 16-bit Intel platforms.

WPP

the Open Watcom C++ compiler for 16-bit Intel platforms.

WCC386

the Open Watcom C compiler for 32-bit Intel platforms.

WPP386

the Open Watcom C++ compiler for 32-bit Intel platforms.


Compiler Options - Indexed

In this section, we present an index of all compiler options.

0

1

2

3

4

5

6

3{r|s}

4{r|s}

5{r|s}

6{r|s}

ad[=<file_name>]

add[=<file_name>]

adhp[=<path_name>]

adt[=<target_name>]

adbs

adfs

bc

bd

bg

bm

br

bt[=<os>]

bw

d0

d1

d1+

d2

d2i

d2s

d2t

d3

d3i

d3s

d<name>[=text]

d+

db

e<number>

ecc

ecd

ecf

ecp

ecr

ecs

ecw

ee

ef

ei

em

en

ep[<number>]

eq

er

et

ew

ez

fc=<file_name>

fh[q][=<file_name>]

fhd

fhr

fhw

fhwe

fi=<file_name>

fo[=<file_name>] (preprocessor)

fo[=<file_name>]

fpc

fpi

fpi87

fp2

fp3

fp5

fp6

fpd

fpr

fr[=<file_name>]

ft

fti

fx

fzh

fzs

g=<codegroup>

h{w,d,c}

i=<directory>

j

k

mf

ms

mm

mc

ml

mh

nc=<name>

nd=<name>

nm=<name>

nt=<name>

oa

ob

oc

od

oe=<num>

of

of+

oh

oi

oi+

ok

ol

ol+

om

on

oo

op

or

os

ot

ou

ox

oz

oa

pil

p{e,l,c,w=<num>}

q

r

ri

s

sg

st

t=<num>

u<name>

v

vc...

w<number>

wcd=<number>

wce=<number>

we

wo

wx

xd

xdt

xds

xr

xs

xst

xss

za

zat

ze

zc

zd{f,p}

zdl

zev

zf

zf{f,p}

zfw

zg

zg{f,p}

zk{0,1,2,l}

zk0u

zku=<codepage>

zl

zld

zlf

zls

zm

zmf

zp[{1,2,4,8,16}]

zpw

zq

zri

zro

zs

zt<number>

zu

zv

zw

zW (optimized)

zWs

zz


Compiler Options - Summarized Alphabetically

In this section, we present a terse summary of compiler options.  This summary is displayed on the screen by simply entering the compiler command name with no arguments.

Option:

Description:

0

(16-bit only) 8088 and 8086 instructions (default for 16-bit) (see 0)

1

(16-bit only) 188 and 186 instructions (see 1)

2

(16-bit only) 286 instructions (see 2)

3

(16-bit only) 386 instructions (see 3)

4

(16-bit only) 486 instructions (see 4)

5

(16-bit only) Pentium instructions (see 5)

6

(16-bit only) Pentium Pro instructions (see 6)

3r

(32-bit only) generate 386 instructions based on 386 instruction timings and use register-based argument passing conventions (see 3{r|s})

3s

(32-bit only) generate 386 instructions based on 386 instruction timings and use stack-based argument passing conventions (see 3{r|s})

4r

(32-bit only) generate 386 instructions based on 486 instruction timings and use register-based argument passing conventions (see 4{r|s})

4s

(32-bit only) generate 386 instructions based on 486 instruction timings and use stack-based argument passing conventions (see 4{r|s})

5r

(32-bit only) generate 386 instructions based on Intel Pentium instruction timings and use register-based argument passing conventions (default for 32-bit) (see 5{r|s})

5s

(32-bit only) generate 386 instructions based on Intel Pentium instruction timings and use stack-based argument passing conventions (see 5{r|s})

6r

(32-bit only) generate 386 instructions based on Intel Pentium Pro instruction timings and use register-based argument passing conventions (see 6{r|s})

6s

(32-bit only) generate 386 instructions based on Intel Pentium Pro instruction timings and use stack-based argument passing conventions (see 6{r|s})

ad[=<file_name>]

generate make style automatic dependency file (see ad[=<file_name>])

adbs

force path separators generated in auto-dependency files to backslashes (see adbs)

add[=<file_name>]

specify source dependency name generated in make style auto-dependency file (see add[=<file_name>])

adhp[=<file_name>]

specify path to use for headers with no path given (see adhp[=<path_name>])

adfs

force path separators generated in auto-dependency files to forward slashes (see adfs)

adt[=<target_name>]

specify target name generated in make style auto-dependency file (see adt[=<target_name>])

bc

build target is a console application (see bc)

bd

build target is a Dynamic Link Library (DLL) (see bd)

bg

build target is a GUI application (see bg)

bm

build target is a multi-thread environment (see bm)

br

build target uses DLL version of C/C++ run-time libraries (see br)

bt[=<os>]

build target for operating system <os> (see bt[=<os>])

bw

build target uses default windowing support (see bw)

d0

(C++ only) no debugging information (see d0)

d1

line number debugging information (see d1)

d1+

(C only) line number debugging information plus typing information for global symbols and local structs and arrays (see d1+)

d2

full symbolic debugging information (see d2)

d2i

(C++ only) d2 and debug inlines; emit inlines as external out-of-line functions (see d2i)

d2s

(C++ only) d2 and debug inlines; emit inlines as static out-of-line functions (see d2s)

d2t

(C++ only) full symbolic debugging information, without type names (see d2t)

d3

full symbolic debugging with unreferenced type names (see d3) ,*

d3i

(C++ only) d3 plus debug inlines; emit inlines as external out-of-line functions (see d3i)

d3s

(C++ only) d3 plus debug inlines; emit inlines as static out-of-line functions (see d3s)

d<name>[=text]

preprocessor #define name [text] (see d<name>[=text])

d+

allow extended -d macro definitions (see d+)

db

generate browsing information (see db)

e<number>

set error limit number (default is 20) (see e<number>)

ecc

set default calling convention to __cdecl (see ecc)

ecd

set default calling convention to __stdcall (see ecd)

ecf

set default calling convention to __fastcall (see ecf)

ecp

set default calling convention to __pascal (see ecp)

ecr

set default calling convention to __fortran (see ecr)

ecs

set default calling convention to __syscall (see ecs)

ecw

set default calling convention to __watcall (default) (see ecw)

ee

call epilogue hook routine (see ee)

ef

use full path names in error messages (see ef)

ei

force enum base type to use at least an int (see ei)

em

force enum base type to use minimum (see em)

en

emit routine name before prologue (see en)

ep[<number>]

call prologue hook routine with number of stack bytes available (see ep[<number>])

eq

do not display error messages (they are still written to a file) (see eq)

er

(C++ only) do not recover from undefined symbol errors (see er)

et

Pentium profiling (see et)

ew

(C++ only) generate less verbose messages (see ew)

ez

(32-bit only) generate Phar Lap Easy OMF-386 object file (see ez)

fc=<file_name>

(C++ only) specify file of command lines to be batch processed (see fc=<file_name>)

fh[q][=<file_name>]

use precompiled headers (see fh[q][=<file_name>])

fhd

store debug info for pre-compiled header once (DWARF only) (see fhd)

fhr

(C++ only) force compiler to read pre-compiled header (see fhr)

fhw

(C++ only) force compiler to write pre-compiled header (see fhw)

fhwe

(C++ only) don't include pre-compiled header warnings when "we" is used (see fhwe)

fi=<file_name>

force file_name to be included (see fi=<file_name>)

fo=<file_name>

set object or preprocessor output file specification (see fo[=<file_name>] (preprocessor)) (see fo[=<file_name>])

fpc

generate calls to floating-point library (see fpc)

fpi

(16-bit only) generate in-line 80x87 instructions with emulation (default)

(32-bit only) generate in-line 387 instructions with emulation (default) (see fpi)

fpi87

(16-bit only) generate in-line 80x87 instructions

(32-bit only) generate in-line 387 instructions (see fpi87)

fp2

generate in-line 80x87 instructions (see fp2)

fp3

generate in-line 387 instructions (see fp3)

fp5

generate in-line 80x87 instructions optimized for Pentium processor (see fp5)

fp6

generate in-line 80x87 instructions optimized for Pentium Pro processor (see fp6)

fpd

enable generation of Pentium FDIV bug check code (see fpd)

fpr

generate 8087 code compatible with older versions of compiler (see fpr)

fr=<file_name>

set error file specification (see fr[=<file_name>])

ft

(C++ only) try truncated (8.3) header file specification (see ft)

fti

(C only) track include file opens (see fti)

fx

(C++ only) do not try truncated (8.3) header file specification (see fx)

fzh

(C++ only) do not automatically append extensions for include files (see fzh)

fzs

(C++ only) do not automatically append extensions for source files (see fzs)

g=<codegroup>

set code group name (see g=<codegroup>)

h{w,d,c}

set debug output format (Open Watcom, Dwarf, Codeview) (see h{w,d,c})

i=<directory>

add directory to list of include directories (see i=<directory>)

j

change char default from unsigned to signed (see j)

k

(C++ only) continue processing files (ignore errors) (see k)

m{f,s,m,c,l,h}

memory model - mf=flat (see mf), ms=small (see ms), mm=medium (see mm), mc=compact (see mc), ml=large (see ml), mh=huge (see mh) (default is "ms" for 16-bit and Netware, "mf" for 32-bit)

nc=<name>

set name of the code class (see nc=<name>)

nd=<name>

set name of the "data" segment (see nd=<name>)

nm=<name>

set module name different from filename (see nm=<name>)

nt=<name>

set name of the "text" segment (see nt=<name>)

o{a,b,c,d,e,f,f+,h,i,i+,k,l,l+,m,n,o,p,r,s,t,u,x,z}

control optimization (see oa) (see of)

pil

preprocessor ignores #line directives (see pil)

p{e,l,c,w=<num>}

preprocess file only, sending output to standard output; "c" include comments; "e" encrypt identifiers (C++ only); "l" include #line directives; w=<num> wrap output lines at <num> columns (zero means no wrap) (see p{e,l,c,w=<num>})

q

operate quietly (see q)

r

save/restore segment registers (see r)

ri

return chars and shorts as ints (see ri)

s

remove stack overflow checks (see s)

sg

generate calls to grow the stack (see sg)

st

touch stack through SS first (see st)

t=<num>

(C++ only) set tab stop multiplier (see t=<num>)

u<name>

preprocessor #undef name (see u<name>)

v

output function declarations to .def file (with typedef names) (see v)

vc...

(C++ only) VC++ compatibility options (see vc...)

w<number>

set warning level number (default is w1) (see w<number>)

wcd=<num>

warning control:  disable warning message <num> (see wcd=<number>)

wce=<num>

warning control:  enable warning message <num> (see wce=<number>)

we

treat all warnings as errors (see we)

wo

(C only) (16-bit only) warn about problems with overlaid code (see wo)

wx

set warning level to maximum setting (see wx)

xd

(C++ only) disable exception handling (default) (see xd)

xdt

(C++ only) disable exception handling (same as "xd") (see xdt)

xds

(C++ only) disable exception handling (table-driven destructors) (see xds)

xr

(C++ only) enable RTTI (see xr)

xs

(C++ only) enable exception handling (see xs)

xst

(C++ only) enable exception handling (direct calls for destruction) (see xst)

xss

(C++ only) enable exception handling (table-driven destructors) (see xss)

z{a,e}

disable/enable language extensions (default is ze) (see za) (see ze)

zat

(C++ only) disable alternative tokens (see zat)

zc

place literal strings in code segment (see zc)

zd{f,p}

allow DS register to "float" or "peg" it to DGROUP (default is zdp) (see zd{f,p})

zdl

(32-bit only) load DS register directly from DGROUP (see zdl)

zev

(C only, Unix extension) enable arithmetic on void derived types (see zev)

zf

(C++ only) let scope of for loop initialization extend beyond loop (see zf)

zf{f,p}

allow FS register to be used (default for all but flat memory model) or not be used (default for flat memory model) (see zf{f,p})

zfw

generate FWAIT instructions on 386 and later (see zfw)

zg

output function declarations to .def (without typedef names) (see zg)

zg{f,p}

allow GS register to be used or not used (see zg{f,p})

zk0

double-byte char support for Kanji (see zk{0,1,2,l})

zk0u

translate Kanji double-byte characters to UNICODE (see zk0u)

zk1

double-byte char support for Chinese/Taiwanese (see zk{0,1,2,l})

zk2

double-byte char support for Korean (see zk{0,1,2,l})

zkl

double-byte char support if current code page has lead bytes (see zk{0,1,2,l})

zku=<codepage>

load UNICODE translate table for specified code page (see zku=<codepage>)

zl

suppress generation of library file names and references in object file (see zl)

zld

suppress generation of file dependency information in object file (see zld)

zlf

add default library information to object files (see zlf)

zls

remove automatically inserted symbols (such as runtime library references) (see zls)

zm

place each function in separate segment (near functions not allowed) (see zm)

zmf

place each function in separate segment (near functions allowed) (see zmf)

zp[{1,2,4,8,16}]

set minimal structure packing (member alignment) (see zp[{1,2,4,8,16}])

zpw

output warning when padding is added in a struct/class (see zpw)

zq

operate quietly (see zq)

zri

inline floating point rounding code (see zri)

zro

omit floating point rounding code (see zro)

zs

syntax check only (see zs)

zt<number>

set data threshold (default is zt32767) (see zt<number>)

zu

do not assume that SS contains segment of DGROUP (see zu)

zv

(C++ only) enable virtual function removal optimization (see zv)

zw

Microsoft Windows prologue/epilogue code sequences (see zw)

zW

(16-bit only) Microsoft Windows optimized prologue/epilogue code sequences (see zW (optimized))

zWs

(16-bit only) Microsoft Windows smart callback sequences (see zWs)

zz

remove "@size" from __stdcall function names (10.0 compatible) (see zz)


Compiler Options - Summarized By Category

In the following sections, we present a terse summary of compiler options organized into categories.


Summary:  Target Specific

Option:

Description:

bc

build target is a console application (see bc)

bd

build target is a Dynamic Link Library (DLL) (see bd)

bg

build target is a GUI application (see bg)

bm

build target is a multi-threaded environment (see bm)

br

build target uses DLL version of C/C++ run-time library (see br)

bt[=<os>]

build target for operating system <os> (see bt[=<os>])

bw

build target uses default windowing support (see bw)

of

generate traceable stack frames as needed (see of)

of+

always generate traceable stack frames (see of+)

sg

generate calls to grow the stack (see sg)

st

touch stack through SS first (see st)

zw

generate code for Microsoft Windows (see zw)

zW

(16-bit only) Microsoft Windows optimized prologue/epilogue code sequences (see zW (optimized))

zWs

(16-bit only) Microsoft Windows smart callback sequences (see zWs)


Summary:  Debugging/Profiling

Option:

Description:

d0

(C++ only) no debugging information (see d0)

d1

line number debugging information (see d1)

d1+

(C only) line number debugging information plus typing information for global symbols and local structs and arrays (see d1+)

d2

full symbolic debugging information (see d2)

d2i

(C++ only) d2 and debug inlines; emit inlines as external out-of-line functions (see d2i)

d2s

(C++ only) d2 and debug inlines; emit inlines as static out-of-line functions (see d2s)

d2t

(C++ only) d2 but without type names (see d2t)

d3

full symbolic debugging with unreferenced type names (see d3)

d3i

(C++ only) d3 plus debug inlines; emit inlines as external out-of-line functions (see d3i)

d3s

(C++ only) d3 plus debug inlines; emit inlines as static out-of-line functions (see d3s)

ee

call epilogue hook routine (see ee)

en

emit routine names in the code segment (see en)

ep[<number>]

call prologue hook routine with number stack bytes available (see ep[<number>])

et

Pentium profiling (see et)

h{w,d,c}

set debug output format (Open Watcom, DWARF, Codeview) (see h{w,d,c})

s

remove stack overflow checks (see s)


Summary:  Preprocessor

Option:

Description:

d<name>[=text]

precompilation #define name [text] (see d<name>[=text])

d+

allow extended "d" macro definitions on command line (see d+)

fo[=<file_name>]

set preprocessor output file name (see fo[=<file_name>] (preprocessor))

pil

preprocessor ignores #line directives (see pil)

p{e,l,c,w=<num>}

preprocess file

c

preserve comments

e

encrypt identifiers (C++ only)

l

insert #line directives

w=<num>

wrap output lines at <num> columns.  Zero means no wrap.

(see p{e,l,c,w=<num>})

u<name>

undefine macro name (see u<name>)


Summary:  Diagnostics

Option:

Description:

e<number>

set error limit number (see e<number>)

ef

use full path names in error messages (see ef)

eq

do not display error messages (they are still written to a file) (see eq)

er

(C++ only) do not recover from undefined symbol errors (see er)

ew

(C++ only) alternate error message formatting (see ew)

q

operate quietly (see q)

t=<num>

set tab stop multiplier (see t=<num>)

w<number>

set warning level number (see w<number>)

wcd=<num>

warning control:  disable warning message <num> (see wcd=<number>)

wce=<num>

warning control:  enable warning message <num> (see wce=<number>)

we

treat all warnings as errors (see we)

wx

set warning level to maximum setting (see wx)

z{a,e}

disable/enable language extensions (see za) (see ze)

zq

operate quietly (see zq)

zs

syntax check only (see zs)


Summary:  Source/Output Control

Option:

Description:

ad[=<file_name>]

generate make style auto-dependency file (see ad[=<file_name>])

adbs

force path separators generated in make style auto-dependency file to backslashes (see adbs)

add[=<file_name>]

set source name (the first dependency) for make style auto-dependency file (see add[=<file_name>])

adhp[=<path prefix>]

set default path for header dependencies which result in filename only (see adhp[=<path_name>])

adfs

force path separators generated in make style auto-dependency file to forward slashes (see adfs)

adt[=<target_name>]

specify target name generated in make style auto-dependency file (see adt[=<target_name>])

db

generate browsing information (see db)

ez

generate PharLap EZ-OMF object files (see ez)

fc=<file_name>

(C++ only) specify file of command lines to be batch processed (see fc=<file_name>)

fh[q][=<file_name>]

use precompiled headers (see fh[q][=<file_name>])

fhd

store debug info for pre-compiled header once (DWARF only) (see fhd)

fhr

(C++ only) force compiler to read pre-compiled header (will never write) (see fhr)

fhw

(C++ only) force compiler to write pre-compiled header (will never read) (see fhw)

fhwe

(C++ only) don't include pre-compiled header warnings when "we" is used (see fhwe)

fi=<file_name>

force file_name to be included (see fi=<file_name>)

fo[=<file_name>]

set object or preprocessor output file name (see fo[=<file_name>])

fr[=<file_name>]

set error file name (see fr[=<file_name>])

ft

(C++ only) try truncated (8.3) header file specification (see ft)

fti

(C only) track include file opens (see fti)

fx

(C++ only) do not try truncated (8.3) header file specification (see fx)

fzh

(C++ only) do not automatically append extensions for include files (see fzh)

fzs

(C++ only) do not automatically append extensions for source files (see fzs)

i=<directory>

another include directory (see i=<directory>)

k

continue processing files (ignore errors) (see k)

v

output function declarations to .def (see v)

zat

(C++ only) disable alternative tokens (see zat)

zf

(C++ only) let scope of for loop initialization extend beyond loop (see zf)

zg

generate function prototypes using base types (see zg)

zl

remove default library information (see zl)

zld

remove file dependency information (see zld)

zlf

add default library information to object files (see zlf)

zls

remove automatically generated symbols references (see zls)


Summary:  Code Generation

Option:

Description:

ecc

set default calling convention to __cdecl (see ecc)

ecd

set default calling convention to __stdcall (see ecd)

ecf

set default calling convention to __fastcall (see ecf)

ecp

set default calling convention to __pascal (see ecp)

ecr

set default calling convention to __fortran (see ecr)

ecs

set default calling convention to __syscall (see ecs)

ecw

set default calling convention to __watcall (default) (see ecw)

ei

force enum base type to use at least an int (see ei)

em

force enum base type to use minimum (see em)

j

change char default from unsigned to signed (see j)

ri

return chars and shorts as ints (see ri)

xr

(C++ only) enable RTTI (see xr)

zc

place literal strings in the code segment (see zc)

zp{1,2,4,8,16}

pack structure members (see zp[{1,2,4,8,16}])

zpw

output warning when padding is added in a struct/class (see zpw)

zt<number>

set data threshold (see zt<number>)

zv

(C++ only) enable virtual function removal optimization (see zv)


Summary:  80x86 Floating Point

Option:

Description:

fpc

calls to floating-point library (see fpc)

fpi

in-line 80x87 instructions with emulation (see fpi)

fpi87

in-line 80x87 instructions (see fpi87)

fp2

generate floating-point for 80x87 (see fp2)

fp3

generate floating-point for 387 (see fp3)

fp5

optimize floating-point for Pentium (see fp5)

fp6

optimize floating-point for Pentium Pro (see fp6)

fpd

enable generation of Pentium FDIV bug check code (see fpd)


Summary:  Segments/Modules

Option:

Description:

g=<codegroup>

set code group name (see g=<codegroup>)

nc=<name>

set code class name (see nc=<name>)

nd=<name>

set data segment name (see nd=<name>)

nm=<name>

set module name (see nm=<name>)

nt=<name>

set name of text segment (see nt=<name>)

zm

place each function in separate segment (near functions not allowed) (see zm)

zmf

(C++ only) place each function in separate segment (near functions allowed) (see zmf)


Summary:  80x86 Run-time Conventions

Option:

Description:

0

(16-bit only) 8088 and 8086 instructions (see 0)

1

(16-bit only) 188 and 186 instructions (see 1)

2

(16-bit only) 286 instructions (see 2)

3

(16-bit only) 386 instructions (see 3)

4

(16-bit only) 486 instructions (see 4)

5

(16-bit only) Pentium instructions (see 5)

6

(16-bit only) Pentium Pro instructions (see 6)

3r

(32-bit only) 386 register calling conventions (see 3{r|s})

3s

(32-bit only) 386 stack calling conventions (see 3{r|s})

4r

(32-bit only) 486 register calling conventions (see 4{r|s})

4s

(32-bit only) 486 stack calling conventions (see 4{r|s})

5r

(32-bit only) Pentium register calling conventions (see 5{r|s})

5s

(32-bit only) Pentium stack calling conventions (see 5{r|s})

6r

(32-bit only) Pentium Pro register calling conventions (see 6{r|s})

6s

(32-bit only) Pentium Pro stack calling conventions (see 6{r|s})

m{f,s,m,c,l,h}

memory model (Flat,Small,Medium,Compact,Large,Huge) (see mf)

zdf

DS floats i.e.  not fixed to DGROUP (see zd{f,p})

zdp

DS is pegged to DGROUP (see zd{f,p})

zdl

Load DS directly from DGROUP (see zdl)

zff

FS floats i.e.  not fixed to a segment (see zf{f,p})

zfp

FS is pegged to a segment (see zf{f,p})

zgf

GS floats i.e.  not fixed to a segment (see zg{f,p})

zgp

GS is pegged to a segment (see zg{f,p})

zri

Inline floating point rounding code (see zri)

zro

Omit floating point rounding code (see zro)

zu

SS != DGROUP (see zu)


Summary:  Optimizations

Option:

Description:

oa

relax aliasing constraints (see oa)

ob

enable branch prediction (see ob)

oc

disable <call followed by return> to <jump> optimization (see oc)

od

disable all optimizations (see od)

oe[=<num>]

expand user functions in-line.  <num> controls max size (see oe=<num>)

oh

enable repeated optimizations (longer compiles) (see oh)

oi

expand intrinsic functions in-line (see oi)

oi+

(C++ only) expand intrinsic functions in-line and set inline_depth to maximum (see oi+)

ok

enable control flow prologues and epilogues (see ok)

ol

enable loop optimizations (see ol)

ol+

enable loop optimizations with loop unrolling (see ol+)

om

generate in-line 80x87 code for math functions (see om)

on

allow numerically unstable optimizations (see on)

oo

continue compilation if low on memory (see oo)

op

generate consistent floating-point results (see op)

or

reorder instructions for best pipeline usage (see or)

os

favor code size over execution time in optimizations (see os)

ot

favor execution time over code size in optimizations (see ot)

ou

all functions must have unique addresses (see ou)

ox

equivalent to -obmiler -s (see ox)

oz

NULL points to valid memory in the target environment (see oz)


Summary:  C++ Exception Handling

Option:

Description:

xd

disable exception handling (default) (see xd)

xdt

disable exception handling (same as "xd") (see xdt)

xds

disable exception handling (table-driven destructors) (see xds)

xs

enable exception handling (see xs)

xst

enable exception handling (direct calls for destruction) (see xst)

xss

enable exception handling (table-driven destructors) (see xss)


Summary:  Double-Byte/Unicode Characters

Option:

Description:

zk{0,1,2,l}

double-byte char support:  0=Kanji,1=Chinese/Taiwanese,2=Korean,l=local (see zk{0,1,2,l})

zk0u

translate double-byte Kanji to UNICODE (see zk0u)

zku=<codepage>

load UNICODE translate table for specified code page (see zku=<codepage>)


Summary:  Compatibility with Microsoft Visual C++

Option:

Description:

vc...

VC++ compatibility options (see vc...)

vcap

allow alloca() or _alloca() in a parameter list


Summary:  Compatibility with Older Versions of the 80x86 Compilers

Option:

Description:

r

save/restore segment registers across calls (see r)

fpr

generate backward compatible 80x87 code (see fpr)

zz

generate backward compatible __stdcall conventions by removing the "@size" from __stdcall function names (10.0 compatible) (see zz)


Compiler Options - Full Description

In the following sections, we present complete descriptions of compiler options organized into categories.


Target Specific

This group of options deals with characteristics of the target application; for example, simple executables versus Dynamic Link Libraries, character-mode versus graphical user interface, single-threaded versus multi-threaded, and so on.


bc

(OS/2, Win16/32 only) This option causes the compiler to emit into the object file references to the appropriate startup code for a character-mode console application.  The presence of LibMain/DLLMain or WinMain/wWinMain in the source code does not influence the selection of startup code.  Only main and wmain are significant.

If none of "bc", "bd", "bg" or "bw" are specified then the order of priority in determining which combination of startup code and libraries to use are as follows.

1.	The presence of one of LibMain or DLLMain implies that the DLL startup code and libraries should be used.

2.	The presence of WinMain or wWinMain implies that the GUI startup code and libraries should be used.

3.	The presence of main or wmain implies that the default startup code and libraries should be used.

If both a wide and non-wide version of an entry point are specified, the "wide" entry point will be used.  Thus wWinMain is called when both WinMain and wWinMain are present.  Similarly, wmain is called when both main and wmain are present (and WinMain/wWinMain are not present).  By default, if both wmain and WinMain are included in the source code, then the startup code will attempt to call wWinMain (since both "wide" and "windowed" entry points were included).


bd

(OS/2, Win16/32 only) This option causes the compiler to emit into the object file references to the run-time DLL startup code (reference to the __DLLstart_ symbol) and, if required, special versions of the run-time libraries that support DLLs.  The presence of main/wmain or WinMain/wWinMain in the source code does not influence the selection of startup code.  Only LibMain and DLLMain are significant (see bc).  If you are building a DLL with statically linked C runtime (the default), it is recommended that you compile at least one of its object files with the "bd" switch to ensure that the DLL's C runtime is properly initialized.  The macro __SW_BD will be predefined if "bd" is selected.


bg

(OS/2, Win16/32 only) This option causes the compiler to emit into the object file references to the appropriate startup code for a windowed (GUI) application.  The presence of LibMain/DLLMain or main/wmain in the source code does not influence the selection of startup code.  Only WinMain and wWinMain are significant (see bc).


bm

(Netware, OS/2, Win32 only) This option causes the compiler to emit into the object file references to the appropriate multi-threaded library name(s).  The macros _MT and __SW_BM will be predefined if "bm" is selected.


br

(OS/2, Win32 only) This option causes the compiler to emit into the object file references to the run-time DLL library name(s).  The run-time DLL libraries are special subsets of the Open Watcom C/C++ run-time libraries that are available as DLLs.  When you use this option with an OS/2 application, you must also specify the "CASEEXACT" option to the Open Watcom Linker.  The macros _DLL and __SW_BR will be predefined if "br" is selected.


bt[=<os>]

This option causes the compiler to define the "build" target.  This option is used for cross-development work.  It prevents the compiler from defining the default build target (which is based on the host system the compiler is running on).  The default build targets are:

DOS

when the host operating system is DOS,

OS2

when the host operating system is OS/2,

NT

when the host operating system is Windows NT (including Windows 95),

QNX

when the host operating system is QNX.  or

LINUX

when the host operating system is Linux.

It also prevents the compiler from defining the default target macro.  Instead the compiler defines a macro consisting of the string "<os>" converted to uppercase and prefixed and suffixed with two underscores.  The default target macros are described in the section entitled Open Watcom C/C++ Predefined Macros.

For example, specifying the option:

     bt=foo

would cause the compiler to define the macro

     __FOO__

and prevent it from defining MSDOS , _DOS and __DOS__ if the compiler was being run under DOS, __OS2__ if using the OS/2 hosted compiler, __NT__ if using the Windows NT or Windows 95 hosted compiler, __QNX__ and __UNIX__ if using the QNX hosted version.  or __LINUX__ and __UNIX__ if using the Linux hosted version.  Any string consisting of letters, digits, and the underscore character may be used for the target name.

The compiler will also construct an environment variable called <os>_INCLUDE and see if it has been defined.  If the environment variable is defined then each directory listed in it is searched (in the order that they were specified).  For example, the environment variable WINDOWS_INCLUDE will be searched if bt=WINDOWS option was specified.

Example:

     set windows_include=\watcom\h\win

Include file processing is described in the section entitled Open Watcom C/C++ #include File Processing.

Several target names are recognized by the compiler and perform additional operations.

Target name

Additional operation

DOS

Defines the macros _DOS and MSDOS .

WINDOWS

Same as specifying one of the "zw" options.  Defines the macros _WINDOWS (16-bit only) and __WINDOWS_386__ (32-bit only).

NETWARE

(32-bit only) Causes the compiler to use stack-based calling conventions.  Also defines the macro __NETWARE_386__ .

QNX

Defines the macro __UNIX__ .

LINUX

Defines the macro __UNIX__ .

Specifying "bt" with no target name following restores the default target name.


bw

(Win16 only) This option causes the compiler to import a special symbol so that the default windowing library code is linked into your application.  The presence of LibMain/DLLMain in the source code does not influence the selection of startup code.  Only main, wmain, WinMain and wWinMain are significant (see bc).  The macro __SW_BW will be predefined if "bw" is selected.


of

This option selects the generation of traceable stack frames for those functions that contain calls or require stack frame setup.

(16-bit only) To use Open Watcom's "Dynamic Overlay Manager" (DOS only), you must compile all modules using one of the "of" or "of+" options ("of" is sufficient).

For near functions, the following function prologue sequence is generated.

     (16-bit only)

         push BP

         mov  BP,SP

     (32-bit only)

         push EBP

         mov  EBP,ESP

For far functions, the following function prologue sequence is generated.

     (16-bit only)

         inc  BP

         push BP

         mov  BP,SP

     (32-bit only)

         inc  EBP

         push EBP

         mov  EBP,ESP

The BP/EBP value on the stack will be even or odd depending on the code model.

For 16-bit DOS systems, the Dynamic Overlay Manager uses this information to determine if the return address on the stack is a short address (16-bit offset) or long address (32-bit segment:offset).

Do not use this option for 16-bit Windows applications.  It will alter the code sequence generated for "_export" functions.

Example:

     C>compiler_name toaster /of

The macro __SW_OF will be predefined if "of" is selected.


of+

This option selects the generation of traceable stack frames for all functions regardless of whether they contain calls or require stack frame setup.  This option is intended for developers of embedded systems (ROM-based applications).

To use Open Watcom's "Dynamic Overlay Manager" (16-bit DOS only), you must compile all modules using one of the "of" or "of+" options ("of" is sufficient).

For near functions, the following function prologue sequence is generated.

     (16-bit only)

         push BP

         mov  BP,SP

     (32-bit only)

         push EBP

         mov  EBP,ESP

For far functions, the following function prologue sequence is generated.

     (16-bit only)

         inc  BP

         push BP

         mov  BP,SP

     (32-bit only)

         inc  EBP

         push EBP

         mov  EBP,ESP

The BP/EBP value on the stack will be even or odd depending on the code model.

For 16-bit DOS systems, the Dynamic Overlay Manager uses this information to determine if the return address on the stack is a short address (16-bit offset) or long address (32-bit segment:offset).

Do not use this option for 16-bit Windows applications.  It will alter the code sequence generated for "_export" functions.

Example:

     C>compiler_name toaster /of+


sg

This option is useful for 32-bit OS/2 and Win32 multi-threaded applications.  It requests the code generator to emit a run-time call at the start of any function that has more than 4K bytes of automatic variables (variables located on the stack).

Under 32-bit OS/2, the stack is grown automatically in 4K pages for any threads, other than the primary thread, using the stack "guard page" mechanism.  The stack consists of in-use committed pages topped off with a special guard page.  A memory reference into the 4K guard page causes the operating system to grow the stack by one 4K page and to add a new 4K guard page.  This works fine when there is less than 4K of automatic variables in a function.  When there is more than 4K of automatic data, the stack must be grown in an orderly fashion, 4K bytes at a time, until the stack has grown sufficiently to accommodate all the automatic variable storage requirements.  Hence the requirement for a stack-growing run-time routine.  The stack-growing run-time routine is called __GRO.

The "stack=" linker option specifies how much stack is available and committed for the primary thread when an executable starts.  The stack size parameter to _beginthread() specifies how much stack is available for a child thread.  The child thread starts with just 4k of stack committed.  The stack will not grow to be bigger than the size specified by the stack size parameter.

Under 32-bit Windows (Win32), the stack is grown automatically in 4K pages for all threads using a similar stack "guard page" mechanism.  The stack consists of in-use committed pages topped off with a special guard page.  The techniques for growing the stack in an orderly fashion are the same as that described above for OS/2.

The "stack=" linker option specifies how much stack is available for the primary thread when an executable starts.  The "commit stack=" linker directive specifies how much of that stack is committed when the executable starts.  If no "commit stack=" directive is used, it defaults to the same value as the stack size.  The stack size parameter to _beginthread() specifies how much stack is committed for a child thread.  If the size is set to zero, the size of the primary thread stack is used for the child thread stack.  When the child thread executes, the stack space is not otherwise restricted.

The macro __SW_SG will be predefined if "sg" is selected.


st

This option causes the code generator to ensure that the first reference to the stack in a function is to the stack "bottom" using the SS register.  If the memory for this part of the stack is not mapped to the task, a memory fault will occur involving the SS register.  This permits an operating system to allocate additional stack space to the faulting task.

Suppose that a function requires 100 bytes of stack space.  The code generator usually emits an instruction sequence to reduce the stack pointer by the required number of bytes of stack space, thereby establishing a new stack bottom.  When the "st" option is specified, the code generator will ensure that the first reference to the stack is to a memory location with the lowest address.  If a memory fault occurs, the operating system can determine that it was a stack reference (since the SS register is involved) and also how much additional stack space is required.

See the description of the "sg" option for a more general solution to the stack allocation problem.  The macro __SW_ST will be predefined if "st" is selected.


zw

(16-bit only) This option causes the compiler to generate the prologue/epilogue code sequences required for Microsoft Windows applications.  The following "fat" prologue/epilogue sequence is generated for any functions declared to be "far _export" or "far pascal".

     far pascal func(...)

     far _export func(...)

     far _export pascal func(...)

         push DS

         pop  AX

         nop

         inc  BP

         push BP

         mov  BP,SP

         push DS

         mov  DS,AX

         .

         .

         .

         pop DS

         pop BP

         dec BP

         retf n

The macro __WINDOWS__ will be predefined if "zw" is selected.

(32-bit only) This option causes the compiler to generate any special code sequences required for 32-bit Microsoft Windows applications.  The macro __WINDOWS__ and __WINDOWS_386__ will be predefined if "zw" is selected.


zW (optimized)

(16-bit only) This option is similar to "zw" but causes the compiler to generate more efficient prologue/epilogue code sequences in some cases.  This option may be used for Microsoft Windows applications code other than user callback functions.  Any functions declared as "far _export" will be compiled with the "fat" prologue/epilogue code sequence described under the "zw" option.

     far _export func(...)

     far _export pascal func(...)

The following "skinny" prologue/epilogue sequence is generated for functions that are not declared to be "far _export".

     far pascal func(...)

     far func(...)

         inc  BP

         push BP

         mov  BP,SP

         .

         .

         .

         pop BP

         dec BP

         retf n

The macro __WINDOWS__ will be predefined if "zW" is selected.


zWs

(16-bit only) This option is similar to "zW" but causes the compiler to generate "smart callbacks".  This option may be used for Microsoft Windows user callback functions in executables only.  It is not permitted for DLLs.  Normally, a callback function cannot be called directly.  You must use MakeProcInstance to obtain a function pointer with which to call the callback function.

If you specify "zWs" then you do not need to use MakeProcInstance in order to call your own callback functions.  Any functions declared as "far _export" will be compiled with the "smart" prologue code sequence described here.

The following example shows the usual prologue code sequence that is generated when the "zWs" option is NOT used.

Example:

     compiler_name winapp /mc /bt=windows /d1

     short FAR PASCAL __export Function1( short var1,

                                          long varlong,

                                          short var2 )

     {

      0000  1e            FUNCTION1       push    ds

      0001  58                            pop     ax

      0002  90                            nop

      0003  45                            inc     bp

      0004  55                            push    bp

      0005  89 e5                         mov     bp,sp

      0007  1e                            push    ds

      0008  8e d8                         mov     ds,ax

The following example shows the "smart" prologue code sequence that is generated when the "zWs" option is used.  The assumption here is that the SS register contains the address of DGROUP.

Example:

     compiler_name winapp /mc /bt=windows /d1 /zWs

     short FAR PASCAL __export Function1( short var1,

                                          long varlong,

                                          short var2 )

     {

      0000  8c d0         FUNCTION1       mov     ax,ss

      0002  45                            inc     bp

      0003  55                            push    bp

      0004  89 e5                         mov     bp,sp

      0006  1e                            push    ds

      0007  8e d8                         mov     ds,ax


Debugging/Profiling

This group of options deals with all the forms of debugging information that can be included in an object file.  Support for profiling of Pentium code is also described.


d0

(C++ only) No debugging information is included in the object file.


d1

Line number debugging information is included in the object file.  This option provides additional information to the Open Watcom Debugger (at the expense of larger object files and executable files).  Line numbers are handy when debugging your application with the Open Watcom Debugger at the source code level.  Code speed is not affected by this option.  To avoid recompiling, the Open Watcom Strip Utility can be used to remove debugging information from the executable image.


d1+

(C only) Line number debugging information plus typing information for global symbols and local structs and arrays is included in the object file.  Although global symbol information can be made available to the Open Watcom Debugger through a Open Watcom Linker option, typing information for global symbols and local structs and arrays must be requested when the source file is compiled.  This option provides additional information to the Open Watcom Debugger (at the expense of larger object files and executable files).  Code speed is not affected by this option.  To avoid recompiling, the Open Watcom Strip Utility can be used to remove debugging information from the executable image.


d2

In addition to line number information, local symbol and data type information is included in the object file.  Although global symbol information can be made available to the Open Watcom Debugger through a Open Watcom Linker option, local symbol and typing information must be requested when the source file is compiled.  This option provides additional information to the Open Watcom Debugger (at the expense of larger object files and executable files).

By default, the compiler will select the "od" level of optimization if "d2" is specified (see the description of the "od" option).  Starting with version 11.0, the compiler now expands functions in-line where appropriate.  This means that symbolic information for the in-lined function will not be available.

The use of this option will make the debugging chore somewhat easier at the expense of code speed and size.  To create production code, you should recompile without this option.


d2i

(C++ only) This option is identical to "d2" but does not permit in-lining of functions.  Functions are emitted as external out-of-line functions.  This option can result in larger object and/or executable files than with "d2" (we are discussing both "code" and "file" size here).


d2s

(C++ only) This option is identical to "d2" but does not permit in-lining of functions.  Functions are emitted as static out-of-line functions.  This option can result in larger object and/or executable files than with "d2" or "d2i" (we are discussing both "code" and "file" size here).  Link times are faster than "d2i" (fewer segment relocations) but executables are slightly larger.


d2t

(C++ only) This option is identical to "d2" but does not include type name debugging information.  This option can result in smaller object and/or executable files (we are discussing "file" size here).


d3

This option is identical to "d2" but also includes symbolic debugging information for unreferenced type names.  Note that this can result in very large object and/or executable files when header files like WINDOWS.H or OS2.H are included.


d3i

(C++ only) This option is identical to "d3" but does not permit in-lining of functions.  Functions are emitted as external out-of-line functions.  This option can result in larger object and/or executable files than with "d3" (we are discussing both "code" and "file" size here).


d3s

(C++ only) This option is identical to "d3" but does not permit in-lining of functions.  Functions are emitted as static out-of-line functions.  This option can result in larger object and/or executable files than with "d3" or "d3i" (we are discussing both "code" and "file" size here).  Link times are faster than "d3i" (fewer segment relocations) but executables are slightly larger.


ee

This option causes the compiler to generate a call to __EPI in the epilogue sequence at the end of every function.  This user-written routine can be used to collect/record profiling information.  The macro __SW_EE will be predefined if "ee" is selected.


en

The compiler will emit the function name into the object code as a string of characters just before the function prologue sequence is generated.  The string is terminated by a byte count of the number of characters in the string.

         ; void Toaster( int arg )

                 db      "Toaster", 7

         public  Toaster

         Toaster label   byte

                 .

                 .

                 .

                 ret

This option is intended for developers of embedded systems (ROM-based applications).  It may also be used in conjunction with the "ep" option for special user-written profiling applications.  The macro __SW_EN will be predefined if "en" is selected.


ep[<number>]

This option causes the compiler to generate a call to a user-written __PRO routine in the prologue sequence at the start of every function.  This routine can be used to collect/record profiling information.  The optional argument <number> can be used to cause the compiler to allocate that many bytes on the stack as a place for __PRO to store information.  The macro __SW_EP will be predefined if "ep" is selected.


et

(Pentium only) This option causes the compiler to generate code into the prolog of each function to count exactly how much time is spent within that function, in clock ticks.  This option is valid only for Pentium compatible processors (i.e., the instructions inserted into the code do not work on 486 or earlier architectures).  The Pentium "rdtsc" opcode is used to obtain the instruction cycle count.

At the end of the execution of the program, a file will be written to the same location as the executable, except with a ".prf" extension.  The contents of the file will look like this:

Example:

               1903894223          1  main

               1785232334    1376153  StageA

               1882249150      13293  StageB

               1830895850       2380  StageC

                225730118         99  StageD

The first column is the total number of clock ticks spent inside of the function during the execution of the program, the second column is the number of times it was called and the third column is the individual function name.  The total number of clock ticks includes time spent within functions called from this function.

The overhead of the profiling can be somewhat intrusive, especially for small leaf functions (i.e., it may skew your results somewhat).


h{w,d,c}

The type of debugging information that is to be included in the object file is one of "Open Watcom", "DWARF" or "Codeview".  The default is "DWARF".

If you wish to use the Microsoft Codeview debugger, then choose the "hc" option (this option causes Codeview Level 4 information to be generated).  It will be necessary to run the Microsoft Debugging Information Compactor, CVPACK, on the executable once the linker has created it.  For information on requesting the linker to automatically run CVPACK, see the section entitled "OPTION CVPACK" in the Open Watcom Linker User's Guide.  Alternatively, you can run CVPACK from the command line.

When linking the application, you must also choose the appropriate Open Watcom Linker DEBUG directive.  See the Open Watcom Linker User's Guide for more information.


s

Stack overflow checking is omitted from the generated code.  By default, the compiler will emit code at the beginning of every function that checks for the "stack overflow" condition.  This option can be used to disable this feature.  The macro __SW_S will be predefined if "s" is selected.


Preprocessor

This group of options deals with the compiler preprocessor.


d<name>[=text]

This option can be used to define a preprocessor macro from the command line.  If =text is not specified, then 1 is assumed.  In other words, specifying /dDBGON is equivalent to specifying /dDBGON=1 on the command line.

If =text is specified, then this option is equivalent to including the following line in your source code.

     #define name text

Consider the following example.

Example:

     d_MODDATE="87.05.04"

The above example is equivalent to a line in the source file containing:

     #define _MODDATE "87.05.04"


d+

The syntax of any "d" option which follows on the command line is extended to include C/C++ tokens as part of "text".  The token string is terminated by a space character.  This permits more complex syntax than is normally allowed.

Example:

     /d+ /d_radx=x*3.1415926/180

This is equivalent to specifying the following in the source code.

Example:

     #define _radx x*3.1415926/180

Open Watcom C++ extends this feature by allowing parameterized macros.  When a parameter list is specified, the "=" character must not be specified.  It also permits immediate definition of the macro as shown in the second line of the example.

Example:

     /d+ /d_rad(x)x*3.1415926/180

     /d+_rad(x)x*3.1415926/180

This is equivalent to specifying the following in the source code.

Example:

     #define _rad(x) x*3.1415926/180


fo[=<file_name>] (preprocessor)

The "fo" option is used with any form of the "p" (preprocessor) option to name the output file drive, path, file name and extension.  If the output file name is not specified, it is constructed from the source file name.  If the output file extension is not specified, it is ".i" by default.

Example:

     C>compiler_name report /p /fo=d:\proj\prep\

A trailing "\" must be specified for directory names.  If, for example, the option was specified as fo=d:\proj\prep then the output file would be called d:\proj\prep.i.  A default filename extension must be preceded by a period (".").

Example:

     C>compiler_name report /p /fo=d:\proj\prep\.cpr


pil

By default, #line directives embedded in source files are processed and will be used as a basis for file name and line number information in error messages, __FILE__ and __LINE__ symbols, etc.  The "pil" option causes the preprocessor to ignore #line directives and refer to actual file names and line numbers.


p{e,l,c,w=<num>}

The input file is preprocessed and, by default, is written to the standard output file.  The "fo" option may be used to redirect the output to a file with default extension ".i".

Specify "pc" if you wish to include the original source comments in the Open Watcom C/C++ preprocessor output file.

(C++ Only) Specify "pe" if you wish to encrypt the original identifiers when they are written to the Open Watcom C/C++ preprocessor output file.

Specify "pl" if you wish to include #line directives.

Specify "pcl" or "plc" if you wish both source comments and #line directives.

Use the "w=<num>" suffix if you wish to wish output lines to wrap at <num> columns.  Zero means no wrap.

Example:

     C>compiler_name report /pcelw=80

The input file is preprocessed only.  When only "p" is specified, source comments and #line directives are not included.  You must request these using the "c" and "l" suffixes.  When the output of the preprocessor is fed into the compiler, the #line directive enables the compiler to issue diagnostics in terms of line numbers of the original source file.

The options which are supported when the Open Watcom C/C++ preprocessor is requested are:  "d", "fi", "fo", "i", "m?", and "u".


u<name>

The "u" option may be used to turn off the definition of a predefined macro.  If no name is specified then all predefined macros are undefined.

Example:

     C>compiler_name report /uM_I386


Diagnostics

This group of options deals with the control of compiler diagnostics.


e<number>

The compiler will stop compilation after reaching <number> errors.  By default, the compiler will stop compilation after 20 errors.


ef

This option causes the compiler to display full path names for files in error messages.


eq

This option causes the compiler to not display error messages on the console; however, they are still written to a file (see fr[=<file_name>]).


er

(C++ only) This option causes the C++ compiler to not recover from undefined symbol errors.  By default, the compiler recovers from "undefined symbol" errors by injecting a special entry into the symbol table that prevents further issuance of diagnostics relating to the use of the same name.  Specify the "er" option if you want all uses of the symbol to be diagnosed.

Example:

     struct S {

     };

     void foo( S *p ) {

         p->m = 1; // member 'm' has not been declared in 'S'

     }

     void bar( S *p ) {

         p->m = 2; // no error unless "er" is specified

     }


ew

(C++ only) This option causes the C++ compiler to generate equivalent but less verbose diagnostic messages.


q

This option is equivalent to the "zq" option (see zq).


t=<num>

(C++ only) The "t" option is used to set the tab stop interval.  By default, the compiler assumes a tab stop occurs at multiples of 8 (1+n x 8 = 1, 9, 17, ...  for n=0, 1, 2, ...).  When the compiler reports a line number and column number in a diagnostic message, the column number has been adjusted for intervening tabs.  If the default tab stop setting for your text editor is not a multiple of 8, then you should use this option.

Example:

     C>compiler_name report /t=4


w<number>

The compiler will issue only warning type messages of severity <number> or below.  Type 1 warning messages are the most severe while type 3 warning messages are the least severe.  Specify "w0" to prevent warning messages from being issued.  Specify "wx" to obtain all warning messages.


wcd=<number>

The compiler will not issue the warning message indicated by <number>.


wce=<number>

The compiler will issue the warning message indicated by <number> despite any pragmas that may have disabled it.


we

By default, the compiler will continue to create an object file when there are warnings produced.  This option can be used to treat all warnings as errors, thereby preventing the compiler from creating an object file if there are warnings found within a module.


wo

(C only) (16-bit only) This option tells the compiler to emit warnings for things that will cause problems when compiling code for use in overlays.


wx

This option sets the warning level to its maximum setting.


za

This option helps to ensure that the module to be compiled conforms to the ISO/ANSI C or C++ programming language specification (depending on the compiler which is selected).  The macro NO_EXT_KEYS (no extended keywords) will be predefined if "za" is selected.  The "ou" option will be enabled (see ou).  See also the description of the "ze" option.

When using the C compiler, there is an exception to the enforcement of the ISO C standard programming language specification.  The use of C++ style comments (// comment) are not diagnosed.


ze

The "ze" option (default) enables the use of the following compiler extensions:

1.	The requirement for at least one external definition per module is relaxed.

2.	When using the C compiler, some forgiveable pointer type mismatches become warnings instead of errors.

3.	In-line math functions are allowed (note that errno will not be set by in-line functions).

4.	When using the C compiler, anonymous structs/unions are allowed (this is always permitted in C++).

Example:

     struct {

         int a;

         union {

             int   b;

             float alt_b;

         };

         int c;

     } x;

In the above example, "x.b" is a valid reference to the "b" field.

5.	For C only, ISO function prototype scope rules are relaxed to allow the following program to compile without any errors.

Example:

     void foo( struct a *__p );

     struct a {

         int b;

         int c;

     };

     void bar( void )

     {

         struct a x;

         foo( &x );

     }

According to a strict interpretation of the ISO C standard, the function prototype introduces a new scope which is terminated at the semicolon (;).  The effect of this is that the structure tag "a" in the function "foo" is not the same structure tag "a" defined after the prototype.  A diagnostic must be issued for a conforming ISO C implementation.

6.	A trailing comma (,) is allowed after the last constant in an enum declaration.

Example:

     enum colour { RED, GREEN, BLUE, };

7.	The ISO requirement that all enums have a base type of int is relaxed.  The motivation for this extension is conservation of storage.  Many enums can be represented by integral types that are smaller in size than an int.

Example:

     enum colour { RED, GREEN, BLUE, };

     void foo( void )

     {

         enum colour x;

         x = RED;

     }

In the example, "x" can be stored in an unsigned char because its values span the range 0 to 2.

8.	The ISO requirement that the base type of a bitfield be int or unsigned is relaxed.  This allows a programmer to allocate bitfields from smaller units of storage than an int (e.g., unsigned char).

Example:

     struct {

         unsigned char a : 1;

         unsigned char b : 1;

         unsigned char c : 1;

     } x;

     struct {

         unsigned a : 1;

         unsigned b : 1;

         unsigned c : 1;

     } y;

In the above example, the size of "x" is the same size as an unsigned char whereas the size of "y" is the same size as an unsigned int.

9.	The following macros are defined.

     _near, near

     _far, far, SOMDLINK (16-bit)

     _huge, huge

     _based

     _segment

     _segname

     _self

     _cdecl, cdecl, SOMLINK (16-bit)

     _pascal, pascal

     _fastcall

     _fortran, fortran

     _inline

     _interrupt, interrupt

     _export

     _loadds

     _saveregs

     _stdcall

     _syscall, SOMLINK (32-bit), SOMDLINK (32-bit)

     _far16

See also the description of the "za" option.


zq

The "quiet mode" option causes the informational messages displayed by the compiler to be suppressed.  Normally, messages are displayed identifying the compiler and summarizing the number of lines compiled.  As well, a dot is displayed every few seconds while the code generator is active, to indicate that the compiler is still working.  These messages are all suppressed by the "quiet mode" option.  Error and warning messages are not suppressed.


zs

The compiler will check the source code only and omit the generation of object code.  Syntax checking, type checking, and so on are performed as usual.


Source/Output Control

This group of options deals with control over the input files and output files that the compiler processes and/or creates.


ad[=<file_name>]

This option enables generation of automatic dependency infomation in makefile format, as a list of targets and their dependents.  If the name of the automatic dependency file is not specified, it is constructed from the source file name.  If the dependency extension is not specified, it is ".d" by default.

Example:

     C>compiler_name report /ad=d:\proj\obj\

A trailing "\" must be specified for directory names.  If, for example, the option was specified as fo=d:\proj\obj then the dependency file will be called d:\proj\obj.d.

A default filename extension must be preceded by a period (".").

Example:

     C>compiler_name report /ad=d:\proj\obj\.dep

The content of the generated file has the following format:

Example:

     <targetname>:<input source file> <included header files...>

Note that the header files listed in the dependency file normally do not include the standard library headers.


adbs

When generating make style automatic dependency files, this option forces all path separators ("/" or "\") to be a backslash ("\").  Certain usage may result in mixed path separators; this options helps generating automatic dependency information in a format appropriate for the make tool used.


add[=<file_name>]

Set the first dependency name in a make style automatic dependency file.  By default, the name of the source file to be compiled is used.  (see ad[=<file_name>])


adhp[=<path_name>]

When including a file with "" delimiters, the resulting filename in make style automatic dependency files will have no path.  This option allows such files to be given a path; said path may be relative.  The path_name argument is directly prepended to the filename, therefore a trailing path separator must be specified.

This issue only affects headers found in the current directory, that is, the directory current at the time of compilation.  If a header is located in an including file's directory, it will automatically receive a path.

This option is useful in situations where the current directory at the time when the automatic dependency information is evaluated is not the same as the current directory at the time of compilation (i.e., when the automatic dependency information was generated).


adfs

When generating make style automatic dependency files, this option forces all path separators ("/" or "\") to be a forward slash ("/").  Certain usage may result in mixed path separators; this options helps generating automatic dependency information in a format appropriate for the make tool used.


adt[=<target_name>]

This option enables generation of automatic dependency infomation in the form of a makefile.  The target in the makefile can be specified.  If the automatic dependency target is not specified through this option, it is constructed from the source file name.  If the target extension is not specified, it is ".obj" by default.

Example:

     C>compiler_name report /adt=d:\proj\obj\

A trailing "\" must be specified for directory names.  If, for example, the option was specified as fo=d:\proj\obj then the dependency file would be called d:\proj\obj.obj.

A default filename extension must be preceded by a period (".").

Example:

     C>compiler_name report /adt=d:\proj\obj\.dep

The generated file has the following contents:

Example:

     <targetname>:<input source file> <included header files...>

Note that the header files listed in the dependency file normally do not include the standard library headers.


db

Use this option to generate browsing information.  The browsing information is recorded in a file whose name is constructed from the source file name and the extension ".mbr".


ez

(32-bit only) The compiler will generate an object file in Phar Lap Easy OMF-386 (object module format) instead of the default Microsoft OMF.  The macro __SW_EZ will be predefined if "ez" is selected.


fc=<file_name>

(C++ only) The specified "batch" file contains a list of command lines to be processed.  This enables the processing of a number of source files together with options for each file with one single invocation of the compiler.  Only one "fc" option is allowed and no source file names are permitted on the command line.

Example:

     [batch.txt]

     main        /onatx /zp4

     part1 part2 /onatx /zp4 /d1

     part3       /onatx /zp4 /d2

     C>compiler_name /fc=\watcom\h\batch.txt

Each line in the file is treated stand-alone.  In other words, the options from one line do not carry over to another line.  However, any options specified on the command line or the associated compiler environment variable will carry over to the individual command lines in the batch file.  When the compiler diagnoses errors in a source file, processing of subsequent command lines is halted unless the "k" option was specified (see k).


fh[q][=<file_name>]

The compiler will generate/use a precompiled header for the first header file referenced by #include in the source file.  See the chapter entitled Precompiled Headers for more information.


fhd

The compiler will store debug info for the pre-compiled header once (DWARF only).  See the chapter entitled Precompiled Headers for more information.


fhr

(C++ only) This option will force the compiler to read the pre-compiled header if it appears to be up-to-date; otherwise, it will read the header files included by the source code.  It will never write the pre-compiled header (even when it is out-of-date).  See the chapter entitled Precompiled Headers for more information.


fhw

(C++ only) This option will force the compiler to write the pre-compiled header (even when it appears to be up-to-date).  See the chapter entitled Precompiled Headers for more information.


fhwe

(C++ only) This option will ensure that pre-compiled header warnings are not counted as errors when the "we" (treat warnings as errors) option is specified.


fi=<file_name>

The specified file is included as if a

     #include "<file_name>"

directive were placed at the start of the source file.

Example:

     C>compiler_name report /fi=\watcom\h\stdarg.h


fo[=<file_name>]

When generating an object file, the "fo" option may be used to name the object file drive, path, file name and extension.  If the object file name is not specified, it is constructed from the source file name.  If the object file extension is not specified, it is ".obj" by default.

Example:

     C>compiler_name report /fo=d:\proj\obj\

A trailing "\" must be specified for directory names.  If, for example, the option was specified as fo=d:\proj\obj then the object file would be called d:\proj\obj.obj.

A default filename extension must be preceded by a period (".").

Example:

     C>compiler_name report /fo=d:\proj\obj\.dbo


fr[=<file_name>]

The "fr" option is used to name the error file drive, path, file name and extension.  If the error file name is not specified, it is constructed from the source file name.  If the output file extension is not specified, it is ".err" by default.  If no part of the name is specified, then no error file is produced (i.e., /fr disables production of an error file).

Example:

     C>compiler_name report /fr=d:\proj\errs\

A trailing "\" must be specified for directory names.  If, for example, the option was specified as fr=d:\proj\errs then the output file would be called d:\proj\errs.err.  A default filename extension must be preceded by a period (".").

Example:

     C>compiler_name report /fr=d:\proj\errs\.erf


ft

(C++ only) If the compiler cannot open a header file whose file name is longer than 8 letters or whose file extension is longer than 3 letters, it will truncate the name at 8 letters and the extension at 3 letters and try to open a file with the shortened name.  This is the default behaviour for the compiler.

For example, if the compiler cannot open the header file called strstream.h, it will attempt to open a header file called strstrea.h.


fti

(C only) Whenever a file is open as a result of #include directive processing, an informational message is printed.  The message contains the file name and line number identifying where the #include directive was located.


fx

(C++ only) This option can be used to disable the truncated header filename processing that the compiler does by default (see "ft" above).


fzh

(C++ only) This option can be used to stop the compiler from automatically adding extensions to include files.  The default behaviour of the compiler is to search for the specified file, then to try known extensions if the file specifier does not have an extension.  Thus, #include <string> could be matched by 'string', 'string.h' or 'string.hpp' (see "fzs" below).  The macro __SW_FZH will be defined when this switch is used.


fzs

(C++ only) This option can be used to stop the compiler from automatically adding extensions to source files.  The default behaviour of the compiler is to search for the specified file, then to try known extensions if the file specifier does not have an extension.  Thus, 'src_file' could be matched by 'src_file', 'src_file.cpp' or 'src_file.cc' (see "fzh" above).  The macro __SW_FZS will be defined when this switch is used.


i=<directory>

where "<directory>" takes the form

     [d:]path;[d:]path...

The specified paths are added to the list of directories in which the compiler will search for "include" files.  See the section entitled Open Watcom C/C++ #include File Processing for information on directory searching.


k

(C++ only) This option instructs the compiler to continue processing subsequent source files after an error has been diagnosed in the current source file.  See the option fc=<file_name> for information on compiling multiple source files.


v

Open Watcom C will output function declarations to a file with the same filename as the C source file but with extension ".def".  The "definitions" file may be used as an "include" file when compiling other modules in order to take advantage of the compiler's function and argument type checking.


zat

ISO C++ defines a number of alternative tokens that can be used instead of certain traditional tokens.  For example "and" instead of "&&", "or" instead of "||", etc.  See section 2.5 of the ISO C++ 98 standard for the complete list of such tokens.  The "zat" option disables support for these tokens so that the names "and", "or", etc are no longer reserved.


zf

Starting with Open Watcom 1.3, the scope of a variable declared in the initialization expression of a for loop header is by default limited to the body of the loop.  This is in accordance with the ISO C++ standard.  The "zf" option causes the compiler to revert to the behavior it had before Open Watcom 1.3.  In particular, it causes the scope of variables declared in the initialization expression of a for loop header to extend beyond the loop.

Example:

     #include <iostream>

     void f()

     {

       for( int i = 0; i < 10; ++i ) {

         std::cout << i << "\n";

       }

       std::cout << "Value of i at loop termination: " << i << "\n";

     }

The above code will not compile with Open Watcom 1.3 or later because the variable "i" is out of scope in the last output statement.  The "zf" option will allow such code to compile by extending the scope of "i" beyond the loop.


zg

The "zg" option is similar to the "v" option except that function declarations will be output to the "DEF" file using base types (i.e., typedefs are reduced to their base type).

Example:

     typedef unsigned int UINT;

     UINT f( UINT x )

      {

         return( x + 1 );

      }

If you use the "v" option, the output will be:

     extern UINT f(UINT );

If you use the "zg" option, the output will be:

     extern unsigned int f(unsigned int );


zl

By default, the compiler places in the object file the names of the C libraries that correspond to the memory model and floating-point options that were selected.  The Open Watcom Linker uses these library names to select the libraries required to link the application.  If you use the "zl" option, the library names will not be included in the generated object file.

The compiler may generate external references for library code that conveniently cause the linker to link in different code.  One such case is:  if you have any functions that pass or return floating-point values (i.e., float or double), the compiler will insert an external reference that will cause the floating-point formatting routines to be included in the executable.  The "zl" option will disable these external references.

Use this option when you wish to create a library of object modules which do not contain Open Watcom C/C++ library name references.


zld

By default, the compiler places in the object file the names and time stamps of all the files referenced by the source file.  This file dependency information can then be used by WMAKE to determine that this file needs to be recompiled if any of the referenced files has been modified since the object file was created.  This option causes the compiler to not emit this information into the object file.


zlf

The "zlf" option tells the compilers to emit references for all default library information into the compiled object file.  See also the options "zl", "zld" and "zls".


zls

The "zls" option tells the compilers to remove automatically inserted symbols.  These symbols are usually used to force symbol references to be fixed up from the run-time libraries.  An example would be the symbol __DLLstart_, that is inserted into any object file that has a DllMain() function defined within its source file.


Code Generation

This group of options deals with controlling some aspects of the code that is generated by the compiler.


ecc

set default calling convention to __cdecl


ecd

set default calling convention to __stdcall


ecf

set default calling convention to __fastcall


ecp

set default calling convention to __pascal


ecr

set default calling convention to __fortran


ecs

set default calling convention to __syscall


ecw

set default calling convention to __watcall (default)


ei

This option can be used to force the compiler to allocate at least an "int" for all enumerated types.  The macro __SW_EI will be predefined if "ei" is selected.


em

This option can be used to force the compiler to allocate the smallest storage unit required to hold all possible values given for an enumerated list.  This option is the default for the x86 architecture.  The macro __SW_EM will be predefined if "em" is selected.


j

The default char type is changed from an unsigned to a signed quantity.  The macros __CHAR_SIGNED__ and __SW_J will be predefined if "j" is selected.


ri

Functions declared to return integral types such as chars and shorts are promoted to returning ints.  This allows non-ISO-conforming source code which does not properly declare the return types of functions to work properly.  The use of this option should be avoided.


xr

The "xr" option is used to to enable the use of the C++ feature called Run-Time Type Information (RTTI).  RTTI can only be used with classes that have virtual functions declared.  This restriction implies that if you enable RTTI, the amount of storage used for a class in memory does not change.  The RTTI information is added to the virtual function information block so there will be an increase in the executable size if you choose to enable RTTI.  There is no execution penalty at all unless you use the dynamic_cast<> feature in which case, you should be aware that the operation requires a lookup operation in order to perform the conversion properly.  You can mix and match modules compiled with and without "xr", with the caveat that dynamic_cast<> and typeid() may not function (return NULL or throw an exception) if used on a class instance that was not compiled with the "xr" option.


zc

The "zc" option causes the code generator to place literal strings and const items in the code segment.

Example:

     extern const int cvar = 1;

     int var = 2;

     const int ctable[ 5 ] = { 1, 2, 3, 4, 5 };

     char *birds[ 3 ] = { "robin", "finch", "wren" };

In the above example, cvar and ctable and the strings "robin", "finch", etc.  are placed in the code segment.  This option is supported in large data or flat memory models only, or if the item is explicitly "far".  The macro __SW_ZC will be predefined if "zc" is selected.


zp[{1,2,4,8,16}]

The "zp" option allows you to specify the alignment of members in a structure.  The default is "zp2" for the 16-bit compiler and "zp8" for 32-bit compiler.  The alignment of structure members is described in the following table.  If the size of the member is 1, 2, 4, 8 or 16, the alignment is given for each of the "zp" options.  If the member of the structure is an array or structure, the alignment is described by the row "x".

                         zp1     zp2     zp4     zp8     zp16

     sizeof(member)  \---------------------------------------

             1       |   0       0       0       0       0

             2       |   0       2       2       2       2

             4       |   0       2       4       4       4

             8       |   0       2       4       8       8

             16      |   0       2       4       8       16

             x       |   aligned to largest member

An alignment of 0 means no alignment, 2 means word boundary, 4 means doubleword boundary, etc.

Note that packed structures are padded to ensure that consecutive occurrences of the same structure in memory are aligned appropriately.  This is illustrated when the following example is compiled with "zp4".  The amount of padding is determined as follows.  If the largest member of structure "s" is 1 byte then "s" is not aligned.  If the largest member of structure "s" is 2 bytes then "s" is aligned according to row 2.  If the largest member of structure "s" is 4 bytes then "s" is aligned according to row 4.  If the largest member of structure "s" is 8 bytes then "s" is aligned according to row 8.  At present, there are no scalar objects that can have a size of 16 bytes.  If the largest member of structure "s" is an array or structure then "s" is aligned according to row "x".  Padding is the inclusion of slack bytes at the end of a structure in order to guarantee the alignment of consecutive occurrences of the same structure in memory.

To understand why structure member alignment may be important, consider the following example.

Example:

     #include <stdio.h>

     #include <stddef.h>

     typedef struct memo_el {

         char           date[9];

         struct memo_el *prev,*next;

         int            ref_number;

         char           sex;

     } memo;

     void main( )

     {

         printf( "Offset of %s is %d\n",

                 "date", offsetof( memo, date ) );

         printf( "Offset of %s is %d\n",

                 "prev", offsetof( memo, prev ) );

         printf( "Offset of %s is %d\n",

                 "next", offsetof( memo, next ) );

         printf( "Offset of %s is %d\n",

                 "ref_number", offsetof( memo, ref_number ) );

         printf( "Offset of %s is %d\n",

                 "sex", offsetof( memo, sex ) );

         printf( "Size of %s is %d\n",

                 "memo", sizeof( memo ) );

         printf( "Number of padding bytes is %d\n",

                 sizeof( memo )

                 - (offsetof( memo, sex ) + sizeof( char )) );

     }

In the above example, the default alignment "zp8" will cause the pointer and integer items to be aligned on even addresses although the array "date" is 9 bytes in length.  The items are 2-byte aligned when sizeof(item) is 2 and 4-byte aligned when sizeof(item) is 4.

On computer systems that have a 16-bit (or 32-bit) bus, improved performance can be obtained when pointer, integer and floating-point items are aligned on an even boundary.  This could be done by careful rearrangement of the fields of the structure or it can be forced by use of the "zp" option.

     16-bit output when compiled zp1:

     Offset of date is 0

     Offset of prev is 9

     Offset of next is 11

     Offset of ref_number is 13

     Offset of sex is 15

     Size of memo is 16

     Number of padding bytes is 0

     16-bit output when compiled zp4:

     Offset of date is 0

     Offset of prev is 10

     Offset of next is 12

     Offset of ref_number is 14

     Offset of sex is 16

     Size of memo is 18

     Number of padding bytes is 1

     32-bit output when compiled zp1:

     Offset of date is 0

     Offset of prev is 9

     Offset of next is 13

     Offset of ref_number is 17

     Offset of sex is 21

     Size of memo is 22

     Number of padding bytes is 0

     32-bit output when compiled zp4:

     Offset of date is 0

     Offset of prev is 12

     Offset of next is 16

     Offset of ref_number is 20

     Offset of sex is 24

     Size of memo is 28

     Number of padding bytes is 3


zpw

The compiler will output a warning message whenever padding is added to a struct/class for alignment purposes.


zt<number>

The "data threshold" option is used to set the maximum size for data objects to be included in the default data segment.  This option can be used with the compact, large, and huge (16-bit) memory models only.  These are memory models where there can be more than one data segment.  Normally, all data objects whose size is less than or equal to the threshold value are placed in the default data segment "_DATA" unless they are specifically declared to be far items.  When there is a large amount of static data, it is often useful to set the data threshold size so that all objects larger than this size are placed in another (far) data segment.  For example, the option "zt100" causes all data objects larger than 100 bytes in size to be implicitly declared as far and grouped in other data segments.

The default data threshold value is 32767.  Thus, by default, all objects greater than 32767 bytes in size are implicitly declared as far and will be placed in other data segments.  If the "zt" option is specified without a size, the data threshold value is 256.  The largest value that can be specified is 32767 (a larger value will result in 256 being selected).

If the "zt" option is used to compile any module in a program, then you must compile all the other modules in the program with the same option (and value).

Care must be exercised when declaring the size of objects in different modules.  Consider the following declarations in two different C files.  Suppose we define an array in one module as follows:

     extern int Array[100] = { 0 };

and, suppose we reference the same array in another module as follows:

     extern int Array[10];

Assuming that these modules were compiled with the option "zt100", we would have a problem.  In the first module, the array would be placed in another segment since Array[100] is bigger than the data threshold.  In the second module, the array would be placed in the default data segment since Array[10] is smaller than the data threshold.  The extra code required to reference the object in another data segment would not be generated.

Note that this problem can also occur even when the "zt" option is not used (i.e., for objects greater than 32767 bytes in size).  There are two solutions to this problem:  (1) be consistent when declaring an object's size, or, (2) do not specify the size in data reference declarations.


zv

(C++ only) Enable virtual function removal optimization.


80x86 Floating Point

This group of options deals with control over the type of floating-point instructions that the compiler generates.  There are two basic types - floating-point calls (FPC) or floating-point instructions (FPI).  They are selectable through the use of one of the compiler options described below.  You may wish to use the following list when deciding which option best suits your requirements.  Here is a summary of advantages/disadvantages to both.

FPC

1.	not IEEE floating-point

2.	not tailorable to processor

3.	uses coprocessor if present; simulates otherwise

4.	32-bit/64-bit accuracy

5.	runs somewhat faster if coprocessor present

6.	faster emulation (fewer bits of accuracy)

7.	leaner "math" library

8.	fatter application code (calls to library rather than in-line instructions)

9.	application cannot trap floating-point exceptions

10.	ideal for ROM applications

FPI, FPI87

1.	IEEE floating-point

2.	tailorable to processor (see fp2, fp3, fp5, fp6)

3.	uses coprocessor if present; emulates IEEE otherwise

4.	up to 80-bit accuracy

5.	runs "full-tilt" if coprocessor present

6.	slower emulation (more bits of accuracy)

7.	fatter "math" library

8.	leaner application code (in-line instructions)

9.	application can trap floating-point exceptions

10.	ideal for general-purpose applications

To see the difference in the type of code generated, consider the following small example.

Example:

     #include <stdio.h>

     #include <time.h>

     void main()

     {

         clock_t  cstart, cend;

         cstart = clock();

         /*  .

             .

             .

         */

         cend = clock();

         printf( "%4.2f seconds to calculate\n",

                 ((float)cend - cstart) / CLOCKS_PER_SEC );

     }

The following 32-bit code is generated by the Open Watcom C compiler (wcc386) using the "fpc" option.

     main_   push    ebx

             push    edx

             call    clock_

             mov     edx,eax

             call    clock_

             call    __U4FS  ; unsigned 4 to floating single

             mov     ebx,eax

             mov     eax,edx

             call    __U4FS  ; unsigned 4 to floating single

             mov     edx,eax

             mov     eax,ebx

             call    __FSS   ; floating single subtract

             mov     edx,3c23d70aH

             call    __FSM   ; floating single multiply

             call    __FSFD  ; floating single to floating double

             push    edx

             push    eax

             push    offset L1

             call    printf_

             add     esp,0000000cH

             pop     edx

             pop     ebx

             ret

The following 32-bit code is generated by the Open Watcom C compiler (wcc386) using the "fpi" option.

     main_   push    ebx

             push    edx

             sub     esp,00000010H

             call    clock_

             mov     edx,eax

             call    clock_

             xor     ebx,ebx

             mov     [esp],eax

             mov     +4H[esp],ebx

             mov     +8H[esp],edx

             mov     +0cH[esp],ebx

             fild    qword ptr [esp]     ; integer to double

             fild    qword ptr +8H[esp]  ; integer to double

             fsubp   st(1),st            ; subtract

             fmul    dword ptr L2        ; multiply

             sub     esp,00000008H

             fstp    qword ptr [esp]     ; store into memory

             push    offset L1

             call    printf_

             add     esp,0000000cH

             add     esp,00000010H

             pop     edx

             pop     ebx

             ret


fpc

All floating-point arithmetic is done with calls to a floating-point emulation library.  If a numeric data processor is present in the system, it will be used by the library; otherwise floating-point operations are simulated in software.  This option should be used for any of the following reasons:

1.	Speed of floating-point emulation is favoured over code size.

2.	An application containing floating-point operations is to be stored in ROM and an 80x87 will not be present in the system.

The macro __SW_FPC will be predefined if "fpc" is selected.

  Note:  When any module in an application is compiled with the "fpc" option, then all modules must be compiled with the "fpc" option.

  Different math libraries are provided for applications which have been compiled with a particular floating-point option.  See the section entitled Open Watcom C/C++ Math Libraries.

See the section entitled The NO87 Environment Variable for information on testing the floating-point simulation code on personal computers equipped with a coprocessor.


fpi

(16-bit only) The compiler will generate in-line 80x87 numeric data processor instructions into the object code for floating-point operations.  Depending on which library the code is linked against, these instructions will be left as is or they will be replaced by special interrupt instructions.  In the latter case, floating-point will be emulated if an 80x87 is not present.  This is the default floating-point option if none is specified.

(32-bit only) The compiler will generate in-line 387-compatible numeric data processor instructions into the object code for floating-point operations.  When any module containing floating-point operations is compiled with the "fpi" option, coprocessor emulation software will be included in the application when it is linked.

For 32-bit Open Watcom Windows-extender applications or 32-bit applications run in Windows 3.1 DOS boxes, you must also include the WEMU387.386 file in the [386enh] section of the SYSTEM.INI file.

Example:

     device=C:\WATCOM\binw\wemu387.386

Note that the WDEBUG.386 file which is installed by the Open Watcom Installation software contains the emulation support found in the WEMU387.386 file.

Thus, a math coprocessor need not be present at run-time.  This is the default floating-point option if none is specified.  The macros __FPI__ and __SW_FPI will be predefined if "fpi" is selected.

  Note:  When any module in an application is compiled with a particular "floating-point" option, then all modules must be compiled with the same option.

  If you wish to have floating-point emulation software included in the application, you should select the "fpi" option.  A math coprocessor need not be present at run-time.

  Different math libraries are provided for applications which have been compiled with a particular floating-point option.  See the section entitled Open Watcom C/C++ Math Libraries.

See the section entitled The NO87 Environment Variable for information on testing the math coprocessor emulation code on personal computers equipped with a coprocessor.


fpi87

(16-bit only) The compiler will generate in-line 80x87 numeric data processor instructions into the object code for floating-point operations.  An 8087 or compatible math coprocessor must be present at run-time.  If the "2" option is used in conjunction with this option, the compiler will generate 287 and upwards compatible instructions; otherwise, the compiler will generate 8087 compatible instructions.

(32-bit only) The compiler will generate in-line 387-compatible numeric data processor instructions into the object code for floating-point operations.  When the "fpi87" option is used exclusively, coprocessor emulation software is not included in the application when it is linked.  A 387 or compatible math coprocessor must be present at run-time.

The macros __FPI__ and __SW_FPI87 will be predefined if "fpi87" is selected.  See Note with description of "fpi" option.


fp2

The compiler will generate in-line 80x87 numeric data processor instructions into the object code for floating-point operations.  For Open Watcom compilers generating 16-bit code, this option is the default.  For 32-bit applications, use this option if you wish to support those few 386 systems that are equipped with a 287 numeric data processor ("fp3" is the default for Open Watcom compilers generating 32-bit code).  However, for 32-bit applications, the use of this option will reduce execution performance.  Use this option in conjunction with the "fpi" or "fpi87" options.  The macro __SW_FP2 will be predefined if "fp2" is selected.


fp3

The compiler will generate in-line 387-compatible numeric data processor instructions into the object code for floating-point operations.  For 16-bit applications, the use of this option will limit the range of systems on which the application will run but there are execution performance improvements.  For Open Watcom compilers generating 32-bit code, this option is the default.  Use this option in conjunction with the "fpi" or "fpi87" options.  The macro __SW_FP3 will be predefined if "fp3" is selected.


fp5

The compiler will generate in-line 80x87 numeric data processor instructions into the object code for floating-point operations.  The sequence of floating-point instructions will be optimized for greatest possible performance on the Intel Pentium processor.  For 16-bit applications, the use of this option will limit the range of systems on which the application will run but there are execution performance improvements.  Use this option in conjunction with the "fpi" or "fpi87" options.  The macro __SW_FP5 will be predefined if "fp5" is selected.


fp6

The compiler will generate in-line 80x87 numeric data processor instructions into the object code for floating-point operations.  The sequence of floating-point instructions will be optimized for greatest possible performance on the Intel Pentium Pro processor.  For 16-bit applications, the use of this option will limit the range of systems on which the application will run but there are execution performance improvements.  Use this option in conjunction with the "fpi" or "fpi87" options.  The macro __SW_FP6 will be predefined if "fp6" is selected.


fpd

A subtle problem was detected in the FDIV instruction of Intel's original Pentium CPU.  In certain rare cases, the result of a floating-point divide could have less precision than it should.  Contact Intel directly for more information on the issue.

As a result, the run-time system startup code has been modified to test for a faulty Pentium.  If the FDIV instruction is found to be flawed, the low order bit of the run-time system variable __chipbug will be set.

     extern unsigned __near __chipbug;

If the FDIV instruction does not show the problem, the low order bit will be clear.  If the Pentium FDIV flaw is a concern for your application, there are two approaches that you could take:

1.	You may test the __chipbug variable in your code in all floating-point and memory models and take appropriate action (such as display a warning message or discontinue the application).

2.	Alternately, you can use the "fpd" option when compiling your code.  This option directs the compiler to generate additional code whenever an FDIV instruction is generated which tests the low order bit of __chipbug and, if on, calls the software workaround code in the math libraries.  If the bit is off, an in-line FDIV instruction will be performed as before.

If you know that your application will never run on a defective Pentium CPU, or your analysis shows that the FDIV problem will not affect your results, you need not use the "fpd" option.  The macro __SW_FPD will be predefined if "fpd" is selected.


Segments/Modules

This group of options deals with object file data structures that are generated by the compiler.


g=<codegroup>

The generated code is placed in the group called "<codegroup>".  The default "text" segment name will be "<codegroup>_TEXT" but this can be overridden by the "nt" option.

Example:

     C>compiler_name report /g=RPTGROUP /s

(16-bit only) <<

This is useful when compiling applications for small code models where the total application will contain more than 64 kilobytes of code.  Each group can contain up to 64 kilobytes of code.  The application follows a "mixed" code model since it contains a mix of small and large code (intra-segment and inter-segment calls).  Memory models are described in the chapter entitled 16-bit Memory Models.  The far keyword is used to describe routines that are referenced from one group/segment but are defined in another group/segment.

For small code models, the "s" option should be used in conjunction with the "g" option to prevent the generation of calls to the C run-time "stack overflow check" routine ( __STK ).  You must also avoid calls to other "small code" C run-time library routines since inter-segment "near" calls to C library routines are not possible.

>> (16-bit only)


nc=<name>

The default "code" class name is "CODE".  The small code model "_TEXT" segment and the large code model "module_name_TEXT" segments belong to the "CODE" class.  This option allows you to select a different class name for these code segments.  The name of the "code" class is explicitly set to "<name>".

Note that the default "data" class names are "DATA" (for the "CONST", "CONST2" and "_DATA" segments) and "BSS" (for the "_BSS" segment).  There is no provision for changing the data class names.


nd=<name>

This option permits you to define a special prefix for the "CONST", "CONST2", "_DATA", and "_BSS" segment names.  The name of the group to which these segments belong is also changed from "DGROUP" to "<name>_GROUP".  This option is especially useful in the creation of 16-bit Dynamic Link Library (DLL) routines.

Example:

     C>compiler_name report /nd=spec

In the above example, the segment names become "specCONST", "specCONST2", "spec_DATA", and "spec_BSS" and the group name becomes "spec_GROUP".

By default, the data group "DGROUP" consists of the "CONST", "CONST2", "_DATA", and "_BSS" segments.  The compiler places certain types of data in each segment.  The "CONST" segment contains constant literals that appear in your source code.

Example:

     char *birds[ 3 ] = { "robin", "finch", "wren" };

     printf( "Hello world\n" );

In the above example, the strings "Hello world\n", "robin", "finch", etc.  appear in the "CONST" segment.

The "CONST2" segment contains initialized read-only data.

Example:

     extern const int cvar = 1;

     int var = 2;

     int table[ 5 ] = { 1, 2, 3, 4, 5 };

     char *birds[ 3 ] = { "robin", "finch", "wren" };

In the above example, the constant variable cvar is placed in the "CONST2" segment.

The "_BSS" segment contains uninitialized data such as scalars, structures, or arrays.

Example:

     int var1;

     int array1[ 400 ];

Other data segments containing data, specifically declared to be far or exceeding the data threshold (see "zt" option), are named either "module_nameN_DATA" when using the C compiler or "module_name_DATAN" when using the C++ compiler where "N" is some integral number.

Example:

     int far array2[400];

In the above example, array2 is placed in the segment "report11_DATA" (C) or "report_DATA11" (C++) provided that the module name is "report".

The macro __SW_ND will be predefined if "nd" is selected.


nm=<name>

By default, the object file name and the module name that is placed within it are constructed from the source file name.  When the "nm" option is used, the module name that is placed into the object file is "<name>".  For large code models, the "text" segment name is "<name>_TEXT" unless the "nt" option is used.

In the following example, the preprocessed output from report.c is stored on drive "D" under the name temp.c.  The file is compiled with the "nm" option so that the module name imbedded into the object file is "REPORT" rather than "TEMP".

Example:

     C>compiler_name report /pl /fo=d:\temp.c

     C>compiler_name d:\temp /nm=report /fo=report

Since the "fo" option is also used, the resultant object file is called report.obj.


nt=<name>

The name of the "text" segment is explicitly set to "<name>".  By default, the "text" segment name is "_TEXT" for small code models and "module_name_TEXT" for large code models.

     Application Memory      Code

     Type        Model       Segment

     ----------- -------     -------------------

     16-bit      tiny        _TEXT

     32-bit      flat        _TEXT

     16/32-bit   small       _TEXT

     16/32-bit   medium      module_name_TEXT

     16/32-bit   compact     _TEXT

     16/32-bit   large       module_name_TEXT

     16-bit      huge        module_name_TEXT


zm

The "zm" option instructs the code generator to place each function into a separate segment.

In small code models, the segment name is "_TEXT" by default.

(C only) In large code models, the segment name is composed of the function name concatenated with the string "_TEXT".

(C++ only) In large code models, the segment name is composed of the module name concatenated with the string "_TEXT" and a unique integral number.

The default string "_TEXT" can be altered using the "nt" option (see nt=<name>).

The advantages to this option are:

1.	Since each function is placed in its own segment, functions that are not required by an application are omitted from the executable by the linker (when "OPTION ELIMINATE" is specified).

2.	This can result in smaller executables.

3.	This benefit applies to both small and large code models.

4.	This option allows you to create granular libraries without resorting to placing each function in a separate file.

Example:

     static int foo( int x )

     {

         return x - 1;

     }

     static int near foo1( int x )

     {

         return x + 1;

     }

     int foo2( int y )

     {

         return foo(y) * foo1(y-1);

     }

     int foo3( int x, int y )

     {

         return x + y * x;

     }

The disadvantages to this option are:

1.	The "near call" optimization for static functions in large code models is disabled (e.g., the function foo in the example above will never be "near called".  Static functions will always be "far called" in large code models.

2.	Near static functions will still be "near called" (e.g., the function foo1 is "near called" in the example above).  However, this can lead to problems at link time if the caller function ends up in a different segment from the called function (the linker will issue a message if this is the case).

3.	The "common epilogue" optimization is lost.

4.	The linker "OPTION ELIMINATE" must be specified when linking an application to take advantage of the granularity inherent in object files/libraries compiled with this option.

5.	Any assumptions about relative position of functions are invalid.  Consider the following code which attempts to determine the size of a code region by subtracting function addresses:

Example:

     region_size = (unsigned long)&function2 - (unsigned long)function1;

When "zm" is in effect, region_size may be extremely large or even a negative value.  For the above code to work as intended, both function1 and function2 (and every function intended to be located between them) must reside in a single code segment.

This option can be used in paging environments where special segment ordering may be employed.  The "alloc_text" pragma is often used in conjunction with this option to place functions into specific segments.

The macro __SW_ZM will be predefined if "zm" is selected.


zmf

(C++ only) This option is identical to the "zm" option (see zm) except for the following large code model consideration.

Instead of placing each function in a segment with a different name, the code generator will place each function in a segment with the same name (the name of the module suffixed by "_TEXT").

The advantages to this option are:

1.	All functions in a module will reside in the same physical segment in an executable.

2.	The "near call" optimization for static functions in large code models is not disabled (e.g., the function foo in the example above will be "near called".  Static functions will always be "near called" in large code models.

3.	The problem associated with calling "near" functions goes away since all functions in a module will reside in the same physical segment (e.g., the function foo1 is "near" in the example above).

The disadvantages to this option are:

1.	The size of a physical segment is restricted to 64K in 16-bit applications.  Although this may limit the number of functions that can be placed in the segment, the restriction is only on a "per module" basis.

2.	Although less constricting, the size of a physical segment is restricted to 4G in a 32-bit application.


80x86 Run-time Conventions

This group of options deals with the 80x86 run-time environment.


0

(16-bit only) The compiler will make use of only 8086 instructions in the generated object code.  This is the default.  The resulting code will run on 8086 and all upward compatible processors.  The macro __SW_0 will be predefined if "0" is selected.


1

(16-bit only) The compiler will make use of 186 instructions in the generated object code whenever possible.  The resulting code probably will not run on 8086 compatible processors but it will run on 186 and upward compatible processors.  The macro __SW_1 will be predefined if "1" is selected.


2

(16-bit only) The compiler will make use of 286 instructions in the generated object code whenever possible.  The resulting code probably will not run on 8086 or 186 compatible processors but it will run on 286 and upward compatible processors.  The macro __SW_2 will be predefined if "2" is selected.


3

(16-bit only) The compiler will make use of some 386 instructions and FS or GS (if "zff" or "zgf" options are used) in the generated object code whenever possible.  The code will be optimized for 386 processors.  The resulting code probably will not run on 8086, 186 or 286 compatible processors but it will run on 386 and upward compatible processors.  The macro __SW_3 will be predefined if "3" is selected.


4

(16-bit only) The compiler will make use of some 386 instructions and FS or GS (if "zff" or "zgf" options are used) in the generated object code whenever possible.  The code will be optimized for 486 processors.  The resulting code probably will not run on 8086, 186 or 286 compatible processors but it will run on 386 and upward compatible processors.  The macro __SW_4 will be predefined if "4" is selected.


5

(16-bit only) The compiler will make use of some 386 instructions and FS or GS (if "zff" or "zgf" options are used) in the generated object code whenever possible.  The code will be optimized for the Intel Pentium processor.  The resulting code probably will not run on 8086, 186 or 286 compatible processors but it will run on 386 and upward compatible processors.  The macro __SW_5 will be predefined if "5" is selected.


6

(16-bit only) The compiler will make use of some 386 instructions and FS or GS (if "zff" or "zgf" options are used) in the generated object code whenever possible.  The code will be optimized for the Intel Pentium Pro processor.  The resulting code probably will not run on 8086, 186 or 286 compatible processors but it will run on 386 and upward compatible processors.  The macro __SW_6 will be predefined if "6" is selected.


3{r|s}

(32-bit only) The compiler will generate 386 instructions based on 386 instruction timings (see "4", "5" and "6" below).

If the "r" suffix is specified, the following machine-level code strategy is employed.

•	The compiler will pass arguments in registers whenever possible.  This is the default method used to pass arguments (unless the "bt=netware" option is specified).

•	All registers except EAX are preserved across function calls.

•	When any form of the "fpi" option is used, the result of functions of type "float" and "double" is returned in ST(0).

•	When the "fpc" option is used, the result of a function of type "float" is returned in EAX and the result of a function of type "double" is returned in EDX:EAX.

•	The resulting code will be smaller than that which is generated for the stack-based method of passing arguments (see "3s" below).

•	The default naming convention for all global functions is such that an underscore character ("_") is suffixed to the symbol name.  The default naming convention for all global variables is such that an underscore character ("_") is prefixed to the symbol name.

If the "s" suffix is specified, the following machine-level code strategy is employed.

•	The compiler will pass all arguments on the stack.

•	The EAX, ECX and EDX registers are not preserved across function calls.

•	The FS and GS registers are not preserved across function calls.

•	The result of a function of type "float" is returned in EAX.  The result of a function of type "double" is returned in EDX:EAX.

•	The resulting code will be larger than that which is generated for the register method of passing arguments (see "3r" above).

•	The naming convention for all global functions and variables is modified such that no underscore characters ("_") are prefixed or suffixed to the symbol name.

The "s" conventions are similar to those used by the MetaWare High C 386 compiler.

By default, "r" is selected if neither "r" nor "s" is specified.

The macro __SW_3 will be predefined if "3" is selected.  The macro __SW_3R will be predefined if "r" is selected (or defaulted).  The macro __SW_3S will be predefined if "s" is selected.


4{r|s}

(32-bit only) This option is identical to "3{r|s}" except that the compiler will generate 386 instructions based on 486 instruction timings.  The code is optimized for 486 processors rather than 386 processors.  By default, "r" is selected if neither "r" nor "s" is specified.  The macro __SW_4 will be predefined if "4" is selected.  The macro __SW_3R will be predefined if "r" is selected (or defaulted).  The macro __SW_3S will be predefined if "s" is selected.


5{r|s}

(32-bit only) This option is identical to "3{r|s}" except that the compiler will generate 386 instructions based on Intel Pentium instruction timings.  This is the default.  The code is optimized for Intel Pentium processors rather than 386 processors.  By default, "r" is selected if neither "r" nor "s" is specified.  The macro __SW_5 will be predefined if "5" is selected.  The macro __SW_3R will be predefined if "r" is selected (or defaulted).  The macro __SW_3S will be predefined if "s" is selected.


6{r|s}

(32-bit only) This option is identical to "3{r|s}" except that the compiler will generate 386 instructions based on Intel Pentium Pro instruction timings.  The code is optimized for Intel Pentium Pro processors rather than 386 processors.  By default, "r" is selected if neither "r" nor "s" is specified.  The macro __SW_6 will be predefined if "6" is selected.  The macro __SW_3R will be predefined if "r" is selected (or defaulted).  The macro __SW_3S will be predefined if "s" is selected.


mf

(32-bit only) The "flat" memory model (code and data up to 4 gigabytes) is selected.  By default, the 32-bit compiler will select this memory model unless the target system is Netware in which case "small" is selected.  The following macros will be predefined.

     M_386FM

     _M_386FM

     __FLAT__


ms

The "small" memory model (small code, small data) is selected.  By default, the 16-bit compiler will select this memory model.  When the target system is Netware, the 32-bit compiler will select this memory model.  The following macros will be predefined.

     M_I86SM

     _M_I86SM

     M_386SM

     _M_386SM

     __SMALL__


mm

The "medium" memory model (big code, small data) is selected.  The following macros will be predefined.

     M_I86MM

     __MEDIUM__


mc

The "compact" memory model (small code, big data) is selected.  The following macros will be predefined.

     M_I86CM

     _M_I86CM

     __COMPACT__


ml

The "large" memory model (big code, big data) is selected.  The following macros will be predefined.

     M_I86LM

     __LARGE__


mh

(16-bit only) The "huge" memory model (big code, huge data) is selected.  The following macros will be predefined.

     M_I86HM

     __HUGE__

Memory models are described in the chapters entitled 16-bit Memory Models and 32-bit Memory Models.  Other architectural aspects of the Intel 86 family such as pointer size are discussed in the sections entitled 16-bit:  Sizes of Predefined Types in the chapter entitled 16-bit Assembly Language Considerations or 32-bit:  Sizes of Predefined Types in the chapter entitled 32-bit Assembly Language Considerations.


zd{f,p}

The "zdf" option allows the code generator to use the DS register to point to other segments besides "DGROUP" This is the default in the 16-bit compact, large, and huge memory models (except for 16-bit Windows applications).

The "zdp" option informs the code generator that the DS register must always point to "DGROUP" This is the default in the 16-bit small and medium memory models, all of the 16-bit Windows memory models, and the 32-bit small and flat memory models.  The macro __SW_ZDF will be predefined if "zdf" is selected.  The macro __SW_ZDP will be predefined if "zdp" is selected.


zdl

(32-bit only) The "zdl" option causes generation of code to load the DS register directly from DGROUP (rather than the default run-time call).  This option causes the generation of a segment relocation.  This option is used with the "zdp" option but not the "zdf" option.


zev

The "zev" option is an extension to the Watcom C compiler to allow arithmetic operations on void derived types.  This option has been added for compatibility with some Unix compilers and is not ISO compliant.  The use of this option should be avoided.


zf{f,p}

The "zff" option allows the code generator to use the FS register (default for all but flat memory model).  The "zfp" option informs the code generator that the FS register must not be used (default in flat memory model).  The macro __SW_ZFF will be predefined if "zff" is selected.  The macro __SW_ZFP will be predefined if "zfp" is selected.


zfw

The "zfw" option turns on generation of FWAIT instructions on 386 and later CPUs.  Note that when targeting 286 and earlier, this option has no effect because FWAITs are always required for synchronization between CPU and FPU.

This option generates larger and slower code and should only be used when restartable floating-point exceptions are required.

The macro __SW_ZFW will be predefined if "zfw" is selected.


zg{f,p}

The "zgf" option allows the code generator to use the GS register (default for all memory models).  The "zgp" option informs the code generator that the GS register must not be used.  The macro __SW_ZGF will be predefined if "zgf" is selected.  The macro __SW_ZGP will be predefined if "zgp" is selected.


zri

(32-bit only) The "zri" option inlines the code for floating point rounding.  Normally a function call is generated for each float to int conversion which may not be desirable.

The macro __SW_ZRI will be predefined if "zri" is selected.


zro

The "zro" option omits the code for floating point rounding.  This results in non-conformant code - the rounding mode is not ISO/ANSI C compliant - but the code generated is very fast.

The macro __SW_ZRO will be predefined if "zro" is selected.


zu

The "zu" option relaxes the restriction that the SS register contains the base address of the default data segment, "DGROUP".  Normally, all data items are placed into the group "DGROUP" and the SS register contains the base address of this group.  When the "zu" option is selected, the SS register is volatile (assumed to point to another segment) and any global data references require loading a segment register such as DS with the base address of "DGROUP".

(16-bit only) This option is useful when compiling routines that are to be placed in a Dynamic Link Library (DLL) since the SS register points to the stack segment of the calling application upon entry to the function.

The macro __SW_ZU will be predefined if "zu" is selected.


Optimizations

When specified on the command line, optimization options may be specified individually (oa, oi) or the letters may be strung together (oailt).


oa

Alias checking is relaxed.  When this option is specified, the code optimizer will assume that global variables are not indirectly referenced through pointers.  This assumption may reduce the size of the code that is generated.  The following example helps to illustrate this point.

Example:

     extern int i;

     void rtn( int *pi )

     {

         int k;

         for( k = 0; k < 10; ++k ) {

             (*pi)++;

             i++;

         }

     }

In the above example, if "i" and "*pi" referenced the same integer object then "i" would be incremented by 2 each time through the "for" loop and we would call the pointer reference "*pi" an alias for the variable "i".  In this situation, the compiler could not bind the variable "i" to a register without making sure that the "in-memory" copy of "i" was kept up-to-date.  In most cases, the above situation does not arise.  Rarely would we reference the same variable directly by name and indirectly through a pointer in the same routine.  The "oa" option instructs the code generator that such cases do not arise in the module to be compiled.  The code generator will be able to produce more efficient code when it does not have to worry about the alias "problem".

The macro __SW_OA will be predefined if "oa" is selected.


ob

When the "ob" option is specified, the code generator will try to order the blocks of code emitted such that the "expected" execution path (as determined by a set of simple heuristics) will be straight through, with other cases being handled by jumps to separate blocks of code "out of line".  This will result in better cache utilization on the Pentium.  If the heuristics do not apply to your code, it could result in a performance decrease.


oc

This option may be used to disable the optimization where a "CALL" followed by a "RET" (return) is changed into a "JMP" (jump) instruction.

(16-bit only) This option is required if you wish to link an overlayed program using the Microsoft DOS Overlay Linker.  The Microsoft DOS Overlay Linker will create overlay calls for a "CALL" instruction only.  This option is not required when using the Open Watcom Linker.

The macro __SW_OC will be predefined if "oc" is selected.


od

Non-optimized code sequences are generated.  The resulting code will be much easier to debug when using the Open Watcom Debugger.  By default, the compiler will select "od" if "d2" is specified.  If "d2" is followed by one of the other "o?" options then "od" is overridden.

Example:

     C>compiler_name report /d2 /os

The macro __SW_OD will be predefined if "od" is selected.


oe=<num>

Certain user functions are expanded in-line.  The criteria for which functions are selected for in-line expansion is based on the "size" of the function in terms of the number of "tree nodes" generated by the function.  Functions are internally represented as tree structures, where each operand and each operator is a node of the tree.  For example, the statement a = -b * (c + d) can be represented as a tree with 8 nodes, one for each operand and operator.

The number of "nodes" generated corresponds closely with the number of operators used in an expression.  Functions which require more than "<num>" nodes are not expanded in-line.  The default number is 20.  With larger "<num>" values, more (larger) functions will be expanded in-line.  This optimization is especially useful when locally-referenced functions are small in size.

Example:

     C>compiler_name dhrystone /oe


oh

This option enables repeated optimizations (which can result in longer compiles).


oi

Certain library functions are generated in-line.  You must include the appropriate header file containing the prototype for the desired function so that it will be generated in-line.  The functions that can be generated in-line are:

abs        _disable   div        _enable    fabs       _fmemchr   _fmemcmp   _fmemcpy   _fmemset   _fstrcat   _fstrcmp   _fstrcpy   _fstrlen   inpd (2)   inpw       inp        labs       ldiv (2)   _lrotl (2) _lrotr (2) memchr     memcmp     memcpy     memset (1) movedata   outpd (2)  outpw      outp       _rotl      _rotr      strcat     strchr     strcmp (1) strcpy     strlen

     *1 16-bit only

     *2 32-bit only

The macros __INLINE_FUNCTIONS__ and __SW_OI will be predefined if "oi" is selected.


oi+

(C++ only) This option encompasses "oi" but also sets inline_depth to its maximum (255).  By default, inline_depth is 3.  The inline_depth can also be changed by using the C++ inline_depth pragma.


ok

This option enables flowing of register save (from prologue) down into the function's flow graph.  This means that register save/restores will not be executed when it is not necessary (as can be the case when a function consists of an if-else construct with a simple part that does little and a more complex part that does a lot).


ol

Loop optimizations are performed.  This includes moving loop-invariant expressions outside the loops.  The macro __SW_OL will be predefined if "ol" is selected.


ol+

Loop optimizations are performed including loop unrolling.  This includes moving loop-invariant expressions outside the loops and turning some loops into straight-line code.  The macro __SW_OL will be predefined if "ol+" is selected.


om

Generate in-line 80x87 code for math functions like sin, cos, tan, etc.  If this option is selected, it is the programmer's responsibility to make sure that arguments to these functions are within the range accepted by the fsin, fcos, etc.  instructions since no run-time check is made.  For 16-bit, you must also include the "fp3" option to get in-line 80x87 code (except for fabs).  The functions that can be generated in-line are:

atan  cos   exp   fabs  log10 log   sin   sqrt  tan

The macro __SW_OM will be predefined if "om" is selected.


on

This option allows the compiler to replace floating-point divisions with multiplications by the reciprocal.  This generates faster code, but the result may not be the same because the reciprocal may not be exactly representable.  The macro __SW_ON will be predefined if "on" is selected.


oo

By default, the compiler will abort compilation if it runs low on memory.  This option forces the compiler to continue compilation even when low on memory, however, this can result in very poor code being generated.  The macro __SW_OO will be predefined if "oo" is selected.


op

This option causes the compiler to store intermediate floating-point results into memory in order to generate consistent floating-point results rather than keeping values in the 80x87 registers where they have more precision.  The macro __SW_OP will be predefined if "op" is selected.


or

This option enables reordering of instructions (instruction scheduling) to achieve better performance on pipelined architectures such as the Intel 486 and Pentium processors.  This option is essential for generating fast code for the Intel Pentium processor.  Selecting this option will make it slightly more difficult to debug because the assembly language instructions generated for a source statement may be intermixed with instructions generated for surrounding statements.  The macro __SW_OR will be predefined if "or" is selected.


os

Space is favoured over time when generating code (smaller code but possibly slower execution).  By default, the compiler selects a balance between "space" and "time".  The macro __SW_OS will be predefined if "os" is selected.


ot

Time is favoured over space when generating code (faster execution but possibly larger code).  By default, the compiler selects a balance between "space" and "time".  The macro __SW_OT will be predefined if "ot" is selected.


ou

This option forces the compiler to make sure that all function labels are unique.  Thus the compiler will not place two function labels at the same address even if the code for the two functions are identical.  This option is automatically selected if the "za" option is specified.  The macro __SW_OU will be predefined if "ou" is selected.


ox

The "obmiler" and "s" (no stack overflow checking) options are selected.


oz

This option prevents the compiler from omitting NULL pointer checks on pointer conversions.  By default, the compiler omits NULL pointer checks on pointer conversions when it is safe to do so.  Consider the following example.

     struct B1 {

         int b1;

     };

     struct B2 {

         int b2;

     };

     struct D : B1, B2 {

         int d;

     };

     void clear_D( D *p )

     {

             p->d = 0;

             B1 *p1 = p;

             p1->b1 = 0;

             B2 *p2 = p;

             p2->b2 = 0;

     }

In this example, the C++ compiler must ensure that p1 and p2 become NULL if p is NULL (since no offset adjustment is allowed for a NULL pointer).  However, the first executable statement implies that p is not NULL since, in most operating environments, the executing program would crash at the first executable statement if p was NULL.  The "oz" option will prevent the compiler from omitting the check for a NULL pointer.

The macro __SW_OZ will be predefined if "oz" is selected.

When "ox" is combined with the "on", "oa" and "ot" options ("onatx") and the "zp4" option, the code generator will attempt to give you the fastest executing code possible irrespective of architecture.  Other options can give you architecture specific optimizations to further improve the speed of your code.  Note that specifying "onatx" is equivalent to specifying "onatblimer" and "s".  See the section entitled Benchmarking Hints for more information on generating fast code.


C++ Exception Handling

The "xd..." options disable exception handling.  Consequently, it is not possible to use throw , try , or catch statements, or to specify a function exception specification.  If your program (or a library which it includes) throws exceptions, then one of the "xs..." options should be used to compile all the modules in your program; otherwise, any active objects created within the module will not be destructed during exception processing.

Multiple schemes are possible, allowing experimentation to determine the optimal scheme for particular circumstances.  You can mix and match schemes on a module basis, with the proviso that exceptions should be enabled wherever it is possible that a created object should be destructed by the exception mechanism.


xd

This option disables exception handling.  It is the default option if no exception handling option is specified.  When this option is specified (or defaulted):

•	Destruction of objects is caused by direct calls to the appropriate destructors

•	Destructor functions are implemented with direct calls to appropriate destructors to destruct base classes and class members.


xdt

This option is the same as "xd" (see xd).


xds

This option disables exception handling.  When this option is specified:

•	Destruction of objects is caused by direct calls to the appropriate destructors.

•	Destruction of base classes and class members is accomplished by interpreting tables.

•	This option, in general, generates smaller code, with increased execution time and with more run-time system routines included by the linker.


xs

This option enables exception handling using a balanced scheme.  When this option is specified:

•	Tables are interpreted to effect destruction of temporaries and automatic objects; destructor functions are implemented with direct calls to appropriate destructors to destruct base classes and class members.


xst

This option enables exception handling using a time-saving scheme.  When this option is specified:

•	Destruction of temporaries and automatic objects is accomplished with direct calls to appropriate destructors; destructor functions are implemented with direct calls to appropriate destructors to destruct base classes and class members.

•	This scheme will execute faster, but will use more space in general.


xss

This option enables exception handling using a space-saving scheme.  When this option is specified:

•	Tables are interpreted to effect destruction of temporaries and automatic objects; destruction of base classes and class members is accomplished by interpreting tables.

•	This option, in general, generates smaller code, with increased execution time.


Double-Byte/Unicode Characters

This group of options deals with compile-time aspects of character sets used in the source code.


zk{0,1,2,l}

This option causes the compiler to recognize double-byte characters in strings.  When the compiler scans a text string enclosed in quotes ("), it will recognize the first byte of a double-byte character and suppress lexical analysis of the second byte.  This will prevent the compiler from misinterpreting the second byte as a "\" or quote (") character.

zk, zk0

These options cause the compiler to process strings for Japanese double-byte characters (range 0x81 - 0x9F and 0xE0 - 0xFC).  The characters in the range A0 - DF are single-byte Katakana.

zk1

This option causes the compiler to process strings for Traditional Chinese and Taiwanese double-byte characters (range 0x81 - 0xFC).

zk2

This option causes the compiler to process strings for Korean Hangeul double-byte characters (range 0x81 - 0xFD).

zkl

This option causes the compiler to process strings using the current code page.  If the local character set includes double-byte characters then string processing will check for lead bytes.

The macro __SW_ZK will be predefined if any "zk" option is selected.


zk0u

This option causes the compiler to process strings for Japanese double-byte characters (range 0x81 - 0x9F and 0xE0 - 0xFC).  The characters in the range A0 - DF are single-byte Katakana.  All characters, including Kanji, in wide characters (L'c') and wide strings (L"string") are translated to UNICODE.

When the compiler scans a text string enclosed in quotes ("), it will recognize the first byte of a double-byte character and suppress lexical analysis of the second byte.  This will prevent the compiler from misinterpreting the second byte as a "\" or quote (") character.


zku=<codepage>

Characters in wide characters (L'c') and wide strings (L"string") are translated to UNICODE.  The UNICODE translate table for the specified code page is loaded from a file.  The compiler locates this file by searching the paths listed in the PATH environment variable.  The following table lists the supported code pages.

      codepage | character set   | file name

     -------------------------------------------

         437   | US-ASCII (DOS)  | unicode.437

         850   | Latin-1 (DOS)   | unicode.850

         852   | Latin-2 (DOS)   | unicode.852

        1250   | Latin-2 (Win32) | unicode1.250

        1252   | Latin-1 (Win32) | unicode1.252


Compatibility with Microsoft Visual C++

This group of options deals with compatibility with Microsoft's Visual C++ compiler.


vc...

The "vc" option prefix is used to introduce a set of Microsoft Visual C++ compatibility options.  At present, there is only one:  vcap.


vcap

This options tells the compiler to allow _alloca() to be used in a parameter list.  The optimizer has to do extra work to allow this but since it is rare (and easily worked around if you can), you have to ask the optimizer to handle this case.  You also may get less efficient code in some cases.


Compatibility with Older Versions of the 80x86 Compilers

This group of options deals with compatibility with older versions of Open Watcom's 80x86 compilers.


r

This option instructs the compiler to generate function prologue and epilogue sequences that save and restore any segment registers that are modified by the function.  Caution should be exercised when using this option.  If the value of the segment register being restored matches the value of a segment that was freed within the function, a general protection fault will occur in protected-mode environments.  By default, the compiler does not generate code to save and restore segment registers.  This option is provided for compatibility with the version 8.0 release.  The macro __SW_R will be predefined if "r" is selected.


fpr

Use this option if you want to generate floating-point instructions that will be compatible with version 9.0 or earlier of the compilers.  For more information on floating-point conventions see the sections entitled 16-bit:  Using the 80x87 to Pass Arguments and 32-bit:  Using the 80x87 to Pass Arguments.


zz

Use this option if you want to generate __stdcall function names that will be compatible with version 10.0 of the compilers.  When this option is omitted, all C symbols (extern "C" symbols in C++) are suffixed by "@nnn" where "nnn" is the sum of the argument sizes (each size is rounded up to a multiple of 4 bytes so that char and short are size 4).  When the argument list contains "...", the "@nnn" suffix is omitted.  This convention is compatible with Microsoft.  For more information on the __stdcall convention see the section entitled Open Watcom C/C++ Extended Keywords.


The Open Watcom C/C++ Compilers

This chapter covers the following topics.

•	Command line syntax (see Open Watcom C/C++ Command Line Format)

•	Environment variables used by the compilers (see Environment Variables)

•	Examples of command line syntax (see Open Watcom C/C++ Command Line Examples)

•	Interpreting diagnostic messages (see Compiler Diagnostics)

•	#include file handling (see Open Watcom C/C++ #include File Processing)

•	Using the preprocessor built into the compilers (see Open Watcom C/C++ Preprocessor)

•	System-dependent macros predefined by the compilers (see Open Watcom C/C++ Predefined Macros)

•	Additional keywords supported by the compilers (see Open Watcom C/C++ Extended Keywords)

•	Based pointer support in the compilers (see Based Pointers)

•	Notes about the Code Generator (see The Open Watcom Code Generator)


Open Watcom C/C++ Command Line Format

The formal Open Watcom C/C++ command line syntax is shown below.

     compiler_name [options] [file_spec] [options] [@extra_opts]

The square brackets [ ] denote items which are optional.

compiler_name

is one of the Open Watcom C/C++ compiler command names.

WCC

is the Open Watcom C compiler for 16-bit Intel platforms.

WPP

is the Open Watcom C++ compiler for 16-bit Intel platforms.

WCC386

is the Open Watcom C compiler for 32-bit Intel platforms.

WPP386

is the Open Watcom C++ compiler for 32-bit Intel platforms.

file_spec

is the file name specification of one or more files to be compiled.  If file_spec is specified as the single character ".", an input file is read from standard input and the output file name defaults to stdin.obj.

If no drive is specified, the default drive is assumed.

If no path is specified, the current working directory is assumed.  If the file is not in the current directory, an adjacent "C" directory (i.e., ..\c) is searched if it exists.

If no file extension is specified, the compiler will check for a file with one of the following extensions in the order listed:

.CPP

(C++ only)

.CC

(C++ only)

.C

(C/C++)

If a period "." is specified but not the extension, the file is assumed to have no filename extension.

If only the compiler name is specified then the compiler will display a list of available options.

options

is a list of valid compiler options, each preceded by a slash ("/") or a dash ("-").  Options may be specified in any order.

extra_opts

is the name of an environment variable or file which contains additional command line options to be processed.  If the specified environment variable does not exist, a search is made for a file with the specified name.  If no file extension is included in the specified name, the default file extension is ".occ".  A search of the current directory is made.  If not successful, an adjacent "OCC" directory (i.e., ..\occ) is searched if it exists.


Open Watcom C/C++ DLL-based Compilers

The compilers are also available in Dynamic Link Library (DLL) form.

WCCD

is the DLL version of the Open Watcom C compiler for 16-bit Intel platforms.

WPPDI86

is the DLL version of the Open Watcom C++ compiler for 16-bit Intel platforms.

WCCD386

is the DLL version of the Open Watcom C compiler for 32-bit Intel platforms.

WPPD386

is the DLL version of the Open Watcom C++ compiler for 32-bit Intel platforms.

The DLL versions of the compilers can be loaded from the Open Watcom Integrated Development Environment (IDE) and Open Watcom Make.


Environment Variables

Environment variables can be used to specify commonly used compiler options.  There is one environment variable for each compiler (the name of the environment variable is the same as the compiler name).  The Open Watcom C/C++ environment variable names are:

WCC

used with the Open Watcom C compiler for 16-bit Intel platforms

Example:

     C>set wcc=/d1 /ot

WPP

used with the Open Watcom C++ compiler for 16-bit Intel platforms

Example:

     C>set wpp=/d1 /ot

WCC386

used with the Open Watcom C compiler for 32-bit Intel platforms

Example:

     C>set wcc386=/d1 /ot

WPP386

used with the Open Watcom C++ compiler for 32-bit Intel platforms

Example:

     C>set wpp386=/d1 /ot

The options specified in environment variables are processed before options specified on the command line.  The above examples define the default options to be "d1" (include line number debugging information in the object file), and "ot" (favour time optimizations over size optimizations).

Whenever you wish to specify an option that requires the use of an "=" character, you can use the "#" character in its place.  This is required by the syntax of the "SET" command.

Once a particular environment variable has been defined, those options listed become the default each time the associated compiler is used.  The compiler command line can be used to override any options specified in the environment string.

These environment variables are not examined by the Open Watcom Compile and Link utilities.  Since the Open Watcom Compile and Link utilities pass the relevant options found in their associated environment variables to the compiler command line, their environment variable options take precedence over the options specified in the environment variables associated with the compilers.

Hint:  If you are running DOS and you use the same compiler options all the time, you may find it handy to define the environment variable in your DOS system initialization file, AUTOEXEC.BAT.

If you are running Windows NT, use the "System" icon in the Control Panel to define environment variables.

If you are running OS/2 and you use the same compiler options all the time, you may find it handy to define the environment variable in your OS/2 system initialization file, CONFIG.SYS.


Open Watcom C/C++ Command Line Examples

The following are some examples of using Open Watcom C/C++ to compile C/C++ source programs.

Example:

     C>compiler_name report /d1 /s

The compiler processes report.c(pp) producing an object file which contains source line number information.  Stack overflow checking is omitted from the object code.

Example:

     C>compiler_name /mm /fpc calc

The compiler compiles calc.c(pp) for the Intel "medium" memory model and generates calls to floating-point library emulation routines for all floating-point operations.  Memory models are described in the chapter entitled 16-bit Memory Models.

Example:

     C>compiler_name kwikdraw /2 /fpi87 /oaxt

The compiler processes kwikdraw.c(pp) producing 16-bit object code for an Intel 286 system equipped with an Intel 287 numeric data processor (or any upward compatible 386/387, 486DX, or Pentium system).  While the choice of these options narrows the number of microcomputer systems where this code will execute, the resulting code will be highly optimized for this type of system.

Example:

     C>compiler_name /mf /3s calc

The compiler compiles calc.c(pp) for the Intel 32-bit "flat" memory model.  The compiler will generate 386 instructions based on 386 instruction timings using the stack-based argument passing convention.  The resulting code will be optimized for Intel 386 systems.  Memory models are described in the chapter entitled 32-bit Memory Models.  Argument passing conventions are described in the chapter entitled 32-bit Assembly Language Considerations.

Example:

     C>compiler_name kwikdraw /4r /fpi87 /oaimxt

The compiler processes kwikdraw.c(pp) producing 32-bit object code for an Intel 386-compatible system equipped with a 387 numeric data processor.  The compiler will generate 386 instructions based on 486 instruction timings using the register-based argument passing convention.  The resulting code will be highly optimized for Intel 486 systems.

Example:

     C>compiler_name ..\source\modabs /d2

The compiler processes ..\source\modabs.c(pp) (a file in a directory which is adjacent to the current one).  The object file is placed in the current directory.  Included with the object code and data is information on local symbols and data types.  The code generated is straight-forward, unoptimized code which can be readily debugged with the Open Watcom Debugger.

Example:

     C>set compiler_name=/i#\includes /mc

     C>compiler_name \cprogs\grep.tst /fi=iomods.c

The compiler processes the program contained in the file \cprogs\grep.tst.  The file iomods.c is included as if it formed part of the source input stream.  The include search path and memory model options are defaults each time the compiler is invoked.  The memory model option could be overridden on the command line.  After looking for an "include" file in the current directory, the compiler will search each directory listed in the "i" path.  See the section entitled Open Watcom C/C++ #include File Processing for more information.

Example:

     C>compiler_name grep /fo=..\obj\

The compiler processes the program contained in the file grep.c(pp) which is located in the current directory.  The object file is placed in the directory ..\obj under the name grep.obj.

Example:

     C>compiler_name /dDBG=1 grep /fo=..\obj\.dbo

The compiler processes the program contained in the file grep.c(pp) which is located in the current directory.  The macro "DBG" is defined so that conditional debugging statements that have been placed in the source are compiled.  The object file is placed in the directory ..\obj and its filename extension will be ".dbo" (instead of ".obj").  Selection of a different filename extension permits easy identification of object files that have been compiled with debugging statements.

Example:

     C>compiler_name /g=GKS /s \gks\gopks

The compiler generates code for gopks.c(pp) and places it into the "GKS" group.  If the "g" option had not been specified, the code would not have been placed in any group.  Assume that this file contains the definition of the routine gopengks as follows:

     void far gopengks( int workstation, long int h )

     {

         .

         .

         .

     }

For a small code model, the routine gopengks must be defined in this file as far since it is placed in another group.  The "s" option is also specified to prevent a run-time call to the stack overflow check routine which will be placed in a different code segment at link time.  The gopengks routine must be prototyped by C routines in other groups as

     void far gopengks( int workstation, long int h );

since it will appear in a different code segment.


Benchmarking Hints

The Open Watcom C/C++ compiler contains many options for controlling the code to be produced.  It is impossible to have a certain set of compiler options that will produce the absolute fastest execution times for all possible applications.  With that said, we will list the compiler options that we think will give the best execution times for most applications.  You may have to experiment with different options to see which combination of options generates the fastest code for your particular application.

The recommended options for generating the fastest 16-bit Intel code are:

Pentium Pro

/onatx /oh /oi+ /ei /zp8 /6 /fpi87 /fp6

Pentium

/onatx /oh /oi+ /ei /zp8 /5 /fpi87 /fp5

486

/onatx /oh /oi+ /ei /zp8 /4 /fpi87 /fp3

386

/onatx /oh /oi+ /ei /zp8 /3 /fpi87 /fp3

286

/onatx /oh /oi+ /ei /zp8 /2 /fpi87 /fp2

186

/onatx /oh /oi+ /ei /zp8 /1 /fpi87

8086

/onatx /oh /oi+ /ei /zp8 /0 /fpi87

The recommended options for generating the fastest 32-bit Intel code are:

Pentium Pro

/onatx /oh /oi+ /ei /zp8 /6 /fp6

Pentium

/onatx /oh /oi+ /ei /zp8 /5 /fp5

486

/onatx /oh /oi+ /ei /zp8 /4 /fp3

386

/onatx /oh /oi+ /ei /zp8 /3 /fp3

The "oi+" option is for C++ only.  Under some circumstances, the "ob" and "ol+" optimizations may also give better performance with 32-bit Intel code.

Option "on" causes the compiler to replace floating-point divisions with multiplications by the reciprocal.  This generates faster code (multiplication is faster than division), but the result may not be the same because the reciprocal may not be exactly representable.

Option "oe" causes small user written functions to be expanded in-line rather than generating a call to the function.  Expanding functions in-line can further expose other optimizations that couldn't otherwise be detected if a call was generated to the function.

Option "oa" causes the compiler to relax alias checking.

Option "ot" must be specified to cause the code generator to select code sequences which are faster without any regard to the size of the code.  The default is to select code sequences which strike a balance between size and speed.

Option "ox" is equivalent to "obmiler" and "s" which causes the compiler/code generator to do branch prediction ("ob"), generate 387 instructions in-line for math functions such as sin, cos, sqrt ("om"), expand intrinsic functions in-line ("oi"), perform loop optimizations ("ol"), expand small user functions in-line ("oe"), reorder instructions to avoid pipeline stalls ("or"), and to not generate any stack overflow checking ("s").  Option "or" is very important for generating fast code for the Pentium and Pentium Pro processors.

Option "oh" causes the compiler to attempt repeated optimizations (which can result in longer compiles but more optimal code).

Option "oi+" causes the C++ compiler to expand intrinsic functions in-line (just like "oi") but also sets the inline_depth to its maximum (255).  By default, inline_depth is 3.  The inline_depth can also be changed by using the C++ inline_depth pragma.

Option "ei" causes the compiler to allocate at least an "int" for all enumerated types.

Option "zp8" causes all data to be aligned on 8 byte boundaries.  The default is "zp2" for the 16-bit compiler and "zp8" for 32-bit compiler.  If, for example, "zp1" packing was specified then this would pack all data which would reduce the amount of data memory required but would require extra clock cycles to access data that is not on an appropriate boundary.

Options "0", "1", "2", "3", "4", "5" and "6" emit Intel code sequences optimized for processor-specific instruction set features and timings.  For 16-bit Intel applications, the use of these options may limit the range of systems on which the application will run but there are execution performance improvements.

Options "fp2", "fp3", "fp5" and "fp6" emit Intel floating-point operations targetted at specific features of the math coprocessor in the Intel series.  For 16-bit Intel applications, the use of these options may limit the range of systems on which the application will run but there are execution performance improvements.

Option "fpi87" causes in-line Intel 80x87 numeric data processor instructions to be generated into the object code for floating-point operations.  Floating-point instruction emulation is not included so as to obtain the best floating-point performance in 16-bit Intel applications.

For 32-bit Intel applications, the use of the "fp5" option will give good performance on the Intel Pentium but less than optimal performance on the 386 and 486.  The use of the "5" option will give good performance on the Pentium and minimal, if any, impact on the 386 and 486.  Thus, the following set of options gives good overall performance for the 386, 486 and Pentium processors.

     /onatx /oh /oi+ /ei /zp8 /5 /fp3


Compiler Diagnostics

If the compiler prints diagnostic messages to the screen, it will also place a copy of these messages in a file in your current directory.  The file will have the same file name as the source file and an extension of ".err".  The compiler issues two types of diagnostic messages, namely warnings or errors.  A warning message does not prevent the production of an object file.  However, error messages indicate that a problem is severe enough that it must be corrected before the compiler will produce an object file.  The error file is a handy reference when you wish to correct the errors in the source file.

Just to illustrate the diagnostic features of Open Watcom C/C++, we will modify the "hello" program in such a way as to introduce some errors.

Example:

     #include <stdio.h>

     int main()

       {

          int x;

          printf( "Hello world\n" );

          return( y );

       }

The equivalent C++ program follows:

Example:

     #include <iostream.h>

     #include <iomanip.h>

     int main()

     {

         int x;

         cout << "Hello world" << endl;

         return( y );

     }

In this example, we have added the lines:

     int x;

and

     return( y );

and changed the keyword void to int .

We compile the program with the "warning" option.

Example:

     C>compiler_name hello /w3

For the C program, the following output appears on the screen.

     hello.c(7): Error! E1011: Symbol 'y' has not been declared

     hello.c(5): Warning! W202: Symbol 'x' has been defined, but not

                                referenced

     hello.c: 8 lines, included 174, 1 warnings, 1 errors

For the C++ program, the following output appears on the screen.

     hello.cpp(8): Error! E029: (col 13) symbol 'y' has not been declared

     hello.cpp(9): Warning! W014: (col 1) no reference to symbol 'x'

     hello.cpp(9): Note! N392: (col 1) 'int x' in 'int main( void )'

                   defined in: hello.cpp(6) (col 9)

     hello.cpp: 9 lines, included 1628, 1 warning, 1 error

Here we see an example of both types of messages.  An error and a warning message have been issued.  As indicated by the error message, we require a declarative statement for the identifier y.  The warning message indicates that, while it is not a violation of the rules of C/C++ to define a variable without ever using it, we probably did not intend to do so.  Upon examining the program, we find that:

1.	the variable x should have been assigned a value, and

2.	the variable y has probably been incorrectly typed and should have been entered as x.


Open Watcom C/C++ #include File Processing

When using the #include preprocessor directive, a header is identified by a sequence of characters placed between the "<" and ">" delimiters (e.g., <file>) and a source file is identified by a sequence of characters enclosed by quotation marks (e.g., "file").  Open Watcom C/C++ makes a distinction between the use of "<>" or quotation marks to surround the name of the file to be included.  The search techniques for header files and source files are slightly different.  Consider the following example.

Example:

     #include <stdio.h>  /* a system header file */

     #include "stdio.h"  /* your own header or source file */

You should use "<" and ">" when referring to standard or system header files and quotation marks when referring to your own header and source files.

The character sequence placed between the delimiters in an #include directive represents the name of the file to be included.  The file name may include drive, path, and extension.

It is not necessary to include the drive and path specifiers in the file specification when the file resides on a different drive or in a different directory.  Open Watcom C/C++ provides a mechanism for looking up include files which may be located in various directories and disks of the computer system.  Open Watcom C/C++ searches directories for header and source files in the following order (the search stops once the file has been located):

1.	If the file specification enclosed in quotation marks ("file-spec") or angle brackets (<file-spec>) contains the complete drive and path specification, that file is included (provided it exists).  No other searching is performed.  The drive need not be specified in which case the current drive is assumed.

2.	If the file specification is enclosed in quotation marks, the current directory is searched.

3.	Next, if the file specification is enclosed in quotation marks, the directory of the file containing the #include directive is searched.  If the current file is also an #include file, the directory of the parent file is searched next.  This search continues recursively through all the nested #include files until the original source file's directory is searched.

4.	Next, if the file specification enclosed in quotation marks ("file-spec") or in angle brackets (<file-spec>), each directory listed in the "i" path is searched (in the order that they were specified).

5.	Next, each directory listed in the <os>_INCLUDE environment variable is searched (in the order that they were specified).  The environment variable name is constructed from the current build target name.  The default build targets are:

DOS

when the host operating system is DOS,

OS2

when the host operating system is OS/2,

NT

when the host operating system is Windows NT/95, or

QNX

when the host operating system is QNX.

LINUX

when the host operating system is Linux.

For example, the environment variable OS2_INCLUDE will be searched if the build target is "OS2".  The build target would be OS/2 if:

1.	the host operating system is OS/2 and the "bt" option was not specified, or

2.	the "bt=OS2" option was explicitly specified.

6.	Next, each directory listed in the INCLUDE environment variable is searched (in the order that they were specified).

7.	Finally, if the file specification is enclosed in quotation marks, an adjacent "H" directory (i.e., ..\h) is searched if it exists.

In the above example, <stdio.h> and "stdio.h" could refer to two different files if there is a stdio.h in the current directory and one in the Open Watcom C/C++ include file directory (\WATCOM\H) and the current directory is not listed in an "i" path or the INCLUDE environment variable.

The compiler will search the directories listed in "i" paths (see description of the "i" option) and the INCLUDE environment variable in a manner analogous to that which the operating system shell will use when searching for programs by using the PATH environment variable.

The "SET" command is used to define an INCLUDE environment variable that contains a list of directories.  A command of the form

     SET INCLUDE=[d:]path;[d:]path...

is issued before running Open Watcom C/C++ the first time.  The brackets indicate that the drive "d:" is optional and the ellipsis indicates that any number of paths may be specified.  For Windows NT, use the "System" icon in the Control Panel to define environment variables.

We illustrate the use of the #include directive in the following example.

Example:

     #include <stdio.h>

     #include <time.h>

     #include <dos.h>

     #include "common.c"

     int main()

       {

         initialize();

         update_files();

         create_report();

         finalize();

       }

     #include "part1.c"

     #include "part2.c"

If the above text is stored in the source file report.c in the current directory then we might issue the following commands to compile the application.

Example:

     C>rem -- Two places to look for include files

     C>set include=c:\watcom\h;b:\headers

     C>rem -- Now compile application specifying a

     C>rem    third location for include files

     C>compiler_name report /fo=..\obj\ /i=..\source

In the above example, the "SET" command is used to define the INCLUDE environment variable.  It specifies that the \watcom\h directory (of the "C" disk) and the \headers directory (a directory of the "B" disk) are to be searched.

The Open Watcom C/C++ "i" option defines a third place to search for include files.  The advantage of the INCLUDE environment variable is that it need not be specified each time the compiler is run.


Open Watcom C/C++ Preprocessor

The Open Watcom C/C++ preprocessor forms an integral part of Open Watcom C/C++.  When any form of the "p" option is specified, only the preprocessor is invoked.  No code is generated and no object file is produced.  The output of the preprocessor is written to the standard output file, although it can also be redirected to a file using the "fo" option.  Suppose the following C/C++ program is contained in the file msgid.c.

Example:

     #define _IBMPC 0

     #define _IBMPS2 1

     #if _TARGET == _IBMPS2

     char *SysId = { "IBM PS/2" };

     #else

     char *SysId = { "IBM PC" };

     #endif

     /* Return pointer to System Identification */

     char *GetSysId()

       {

         return( SysId );

       }

We can use the Open Watcom C/C++ preprocessor to generate the C/C++ code that would actually be compiled by the compiler by issuing the following command.

Example:

     C>compiler_name msgid /plc /fo /d_TARGET=_IBMPS2

The file msgid.i will be created and will contain the following C/C++ code.

     #line 1 "msgid.c"

     char *SysId = { "IBM PS/2" };

     #line 9 "msgid.c"

     /* Return pointer to System Identification */

     char *GetSysId()

       {

         return( SysId );

       }

Note that the file msgid.i can be used as input to the compiler.

Example:

     C>compiler_name msgid.i

Since #line directives are present in the file, the compiler can issue error messages in terms of the original source file line numbers.


Open Watcom C/C++ Predefined Macros

In addition to the standard ISO-defined macros supported by the Open Watcom C/C++ compilers, several additional system-dependent macros are also defined.  These are described in this section.  See the Open Watcom C Language Reference manual for a description of the standard macros.

The Open Watcom C/C++ compilers run on various host operating systems including DOS, OS/2, Windows NT, Windows 95 and QNX.  Any of the supported host operating systems can be used to develop applications for a number of target systems.  By default, the target operating system for the application is the same as the host operating system unless some option or combination of options is specified.  For example, DOS applications are built on DOS by default, OS/2 applications are built on OS/2 by default, and so on.  But the flexibility is there to build applications for other operating systems/environments.

The macros described below may be used to identify the target system for which the application is being compiled.  (Note:  In several places in the following text, a pair of underscore characters appears as __ which resembles a single, elongated underscore.)

The Open Watcom C/C++ compilers support both 16-bit and 32-bit application development.  The following macros are defined for 16-bit and 32-bit target systems.

      16-bit      32-bit

     ========    ========

     __X86__     __X86__

     __I86__     __386__

     M_I86       M_I386

     _M_I86      _M_I386

     _M_IX86     _M_IX86

Notes:

1.	The __X86__ identifies the target as an Intel environment.

2.	The __I86__ , M_I86 and _M_I86 macros identify the target as a 16-bit Intel environment.

3.	The __386__ , M_I386 and _M_I386 macros identify the target as a 32-bit Intel environment.

4.	The _M_IX86 macro is identically equal to 100 times the architecture compiler option value (/0, /1, /2, /3, /4, /5, etc.).  If "/5" (Pentium instruction timings) was specified as a compiler option, then the value of _M_IX86 would be 500.

The Open Watcom C/C++ compilers support application development for a variety of operating systems.  The following macros are defined for particular target operating systems.

     Target      Macros

     ======      ======================================

     DOS         __DOS__, _DOS, MSDOS

     OS/2        __OS2__

     QNX         __QNX__, __UNIX__

     Netware     __NETWARE__, __NETWARE_386__

     NT          __NT__

     Windows     __WINDOWS__, _WINDOWS, __WINDOWS_386__

     Linux       __LINUX__, __UNIX__

Notes:

1.	The __DOS__ , _DOS and MSDOS macros are defined when the build target is "DOS" (16-bit DOS or 32-bit extended DOS).

2.	The __OS2__ macro is defined when the build target is "OS2" (16-bit or 32-bit OS/2).

3.	The __QNX__ and __UNIX__ macros are defined when the build target is "QNX" (16-bit or 32-bit QNX).

4.	The __NETWARE__ and __NETWARE_386__ macros are defined when the build target is "NETWARE" (Novell NetWare).

5.	The __NT__ macro is defined when the build target is "NT" (Windows NT and Windows 95).

6.	The __WINDOWS__ macro is defined when the build target is "WINDOWS" or one of the "zw", "zW", "zWs" options is specified (identifies the target operating system as 16-bit Windows or 32-bit extended Windows but not Windows NT or Windows 95).

7.	The _WINDOWS macro is defined when the build target is "WINDOWS" or one of the "zw", "zW", "zWs" options is specified and you are using a 16-bit compiler (identifies the target operating system as 16-bit Windows).

8.	The __WINDOWS_386__ macro is defined when the build target is "WINDOWS" or the "zw" option is specified and you are using a 32-bit compiler (identifies the target operating system as 32-bit extended Windows).

9.	The __LINUX__ and __UNIX__ macros are defined when the build target is "LINUX" (32-bit Linux).

The following macros are defined for the indicated options.

     Option    Macro

     ====== ==================

     bm     _MT

     br     _DLL

     fpi    __FPI__

     fpi87  __FPI__

     j      __CHAR_SIGNED__

     oi     __INLINE_FUNCTIONS__

     xr     _CPPRTTI (C++ only)

     xs     _CPPUNWIND (C++ only)

     xss    _CPPUNWIND (C++ only)

     xst    _CPPUNWIND (C++ only)

     za     NO_EXT_KEYS

     zw     __WINDOWS__

     zW     __WINDOWS__

     zWs    __WINDOWS__

The following memory model macros are defined for the indicated memory model options.

     Option     All        16-bit only          32-bit only

     ====== =========== =================    =================

     mf     __FLAT__                         M_386FM  _M_386FM

     ms     __SMALL__   M_I86SM  _M_I86SM    M_386SM  _M_386SM

     mm     __MEDIUM__  M_I86MM  _M_I86MM    M_386MM  _M_386MM

     mc     __COMPACT__ M_I86CM  _M_I86CM    M_386CM  _M_386CM

     ml     __LARGE__   M_I86LM  _M_I86LM    M_386LM  _M_386LM

     mh     __HUGE__    M_I86HM  _M_I86HM

The following macros indicate which compiler is compiling the C/C++ source code.

__cplusplus

Open Watcom C++ predefines the macro __cplusplus to identify the compiler as a C++ compiler.

__WATCOMC__

Open Watcom C/C++ predefines the macro __WATCOMC__ to identify the compiler as one of the Open Watcom C/C++ compilers.

The value of the macro depends on the version number of the compiler.  The value is 100 times the version number (version 8.5 yields 850, version 9.0 yields 900, etc.).  Note that for Open Watcom 1.0, the value of this macro is 1200, for Open Watcom 1.1 it is 1210 etc.

__WATCOM_CPLUSPLUS__

Open Watcom C++ predefines the macro __WATCOM_CPLUSPLUS__ to identify the compiler as one of the Open Watcom C++ compilers.

The value of the macro depends on the version number of the compiler.  The value is 100 times the version number (version 10.0 yields 1000, version 10.5 yields 1050, etc.).  Note that for Open Watcom 1.0, the value of this macro is 1200, for Open Watcom 1.1 it is 1210 etc.

The following macros are defined for compatibility with Microsoft.

__CPPRTTI

Open Watcom C++ predefines the __CPPRTTI macro to indicate that C++ Run-Time Type Information (RTTI) is in force.  This macro is predefined if the Open Watcom C++ "xr" compile option is specified and is not defined otherwise.

__CPPUNWIND

Open Watcom C++ predefines the __CPPUNWIND macro to indicate that C++ exceptions supported.  This macro is predefined if any of the Open Watcom C++ "xs", "xss" or "xst" compile options are specified and is not defined otherwise.

_INTEGRAL_MAX_BITS

Open Watcom C/C++ predefines the _INTEGRAL_MAX_BITS macro to indicate that maximum number of bits supported in an integral type (see the description of the "__int64" keyword in the next section).  Its value is 64 currently.

_PUSHPOP_SUPPORTED

Open Watcom C/C++ predefines the _PUSHPOP_SUPPORTED macro to indicate that #pragma pack(push) and #pragma pack(pop) are supported.

_STDCALL_SUPPORTED

Open Watcom C/C++ predefines the _STDCALL_SUPPORTED macro to indicate that the standard 32-bit Win32 calling convention is supported.

The following table summarizes the predefined macros supported by the compilers and the values that the respective compilers assign to them.  A "yes" under the column means that the compiler supports the macro with the indicated value.  Note that the C and C++ compilers sometime support the same macro but with different values (including no value which means the symbol is defined without a value).

     Predefined Macro                Supported by Compiler

      and Setting                wcc     wcc386  wpp     wpp386

     --------------------------- ------  ------  ------  ------

     __386__=1                             Yes             Yes

     __3R__=1                                              Yes

     _based=__based                Yes     Yes     Yes     Yes

     _cdecl=__cdecl                Yes     Yes     Yes     Yes

     cdecl=__cdecl                 Yes     Yes     Yes     Yes

     __cplusplus=1                                 Yes     Yes

     _CPPRTTI=1                                    Yes     Yes

     _CPPUNWIND=1                                  Yes     Yes

     _export=__export              Yes     Yes     Yes     Yes

     _far16=__far16                Yes     Yes     Yes     Yes

     _far=__far                    Yes     Yes     Yes     Yes

     far=__far                     Yes     Yes     Yes     Yes

     _fastcall=__fastcall          Yes     Yes     Yes     Yes

     __FLAT__=1                            Yes             Yes

     _fortran=__fortran            Yes     Yes     Yes     Yes

     fortran=__fortran             Yes     Yes     Yes     Yes

     __FPI__=1                     Yes     Yes     Yes     Yes

     _huge=__huge                  Yes     Yes     Yes     Yes

     huge=__huge                   Yes     Yes     Yes     Yes

     __I86__=1                     Yes             Yes

     _inline=__inline              Yes     Yes     Yes     Yes

     _INTEGRAL_MAX_BITS=64         Yes     Yes     Yes     Yes

     _interrupt=__interrupt        Yes     Yes     Yes     Yes

     interrupt=__interrupt         Yes     Yes     Yes     Yes

     _loadds=__loadds              Yes     Yes     Yes     Yes

     _M_386FM=1                                            Yes

     M_386FM=1                                             Yes

     _M_I386=1                             Yes             Yes

     M_I386=1                              Yes             Yes

     _M_I86=1                      Yes             Yes

     M_I86=1                       Yes             Yes

     _M_I86SM=1                    Yes             Yes

     M_I86SM=1                     Yes             Yes

     _M_IX86=0                     Yes             Yes

     _M_IX86=500                           Yes             Yes

     _near=__near                  Yes     Yes     Yes     Yes

     near=__near                   Yes     Yes     Yes     Yes

     __NT__=1 (on Win32 platform)  Yes     Yes     Yes     Yes

     _pascal=__pascal              Yes     Yes     Yes     Yes

     pascal=__pascal               Yes     Yes     Yes     Yes

     _saveregs=__saveregs          Yes     Yes     Yes     Yes

     _segment=__segment            Yes     Yes     Yes     Yes

     _segname=__segname            Yes     Yes     Yes     Yes

     _self=__self                  Yes     Yes     Yes     Yes

     __SMALL__=1                   Yes             Yes

     SOMDLINK=__far                Yes

     SOMDLINK=_Syscall                     Yes             Yes

     SOMLINK=__cdecl               Yes

     SOMLINK=_Syscall                      Yes             Yes

     _STDCALL_SUPPORTED=1                  Yes             Yes

     __SW_0=1                      Yes             Yes

     __SW_3R=1                             Yes             Yes

     __SW_5=1                              Yes             Yes

     __SW_FP287=1                                  Yes

     __SW_FP2=1                    Yes

     __SW_FP387=1                                          Yes

     __SW_FP3=1                            Yes

     __SW_FPI=1                    Yes     Yes     Yes     Yes

     __SW_MF=1                             Yes             Yes

     __SW_MS=1                     Yes

     __SW_ZDP=1                    Yes     Yes     Yes     Yes

     __SW_ZFP=1                    Yes     Yes     Yes     Yes

     __SW_ZGF=1                            Yes             Yes

     __SW_ZGP=1                    Yes             Yes

     _stdcall=__stdcall            Yes     Yes     Yes     Yes

     _syscall=__syscall            Yes     Yes     Yes     Yes

     __WATCOM_CPLUSPLUS__=1290                     Yes     Yes

     __WATCOMC__=1290              Yes     Yes     Yes     Yes

     __X86__=1                     Yes     Yes     Yes     Yes


Open Watcom C/C++ Extended Keywords

Open Watcom C/C++ supports the use of some special keywords to describe system dependent attributes of functions and other object names.  These attributes are inspired by the Intel processor architecture and the plethora of function calling conventions in use by compilers for this architecture.  In keeping with the ISO C and C++ language standards, Open Watcom C/C++ uses the double underscore (i.e., "__") or single underscore followed by uppercase letter (e.g., "_S") prefix with these keywords.  To support compatibility with other C/C++ compilers, alternate forms of these keywords are also supported through predefined macros.

__near

Open Watcom C/C++ supports the __near keyword to describe functions and other object names that are in near memory and pointers to near objects.

Open Watcom C/C++ predefines the macros near and _near to be equivalent to the __near keyword.

__far

Open Watcom C/C++ supports the __far keyword to describe functions and other object names that are in far memory and pointers to far objects.

Open Watcom C/C++ predefines the macros far , _far and SOMDLINK (16-bit only) to be equivalent to the __far keyword.

__huge

Open Watcom C/C++ supports the __huge keyword to describe functions and other object names that are in huge memory and pointers to huge objects.  The 32-bit compilers treat these as equivalent to far objects.

Open Watcom C/C++ predefines the macros huge and _huge to be equivalent to the __huge keyword.

__based

Open Watcom C/C++ supports the __based keyword to describe pointers to objects that appear in other segments or the objects themselves.  See the section entitled Based Pointers for an explanation of the __based keyword.

Open Watcom C/C++ predefines the macro _based to be equivalent to the __based keyword.

__segment

Open Watcom C/C++ supports the __segment keyword which is used when describing objects of type segment.  See the section entitled Based Pointers for an explanation of the __segment keyword.

Open Watcom C/C++ predefines the macro _segment to be equivalent to the __segment keyword.

__segname

Open Watcom C/C++ supports the __segname keyword which is used when describing segname constant based pointers or objects.  See the section entitled Based Pointers for an explanation of the __segname keyword.

Open Watcom C/C++ predefines the macro _segname to be equivalent to the __segname keyword.

__self

Open Watcom C/C++ supports the __self keyword which is used when describing self based pointers.  See the section entitled Based Pointers for an explanation of the __self keyword.

Open Watcom C/C++ predefines the macro _self to be equivalent to the __self keyword.

__restrict

Open Watcom C/C++ provides the __restrict type qualifier as an alternative to the ISO C99 restrict keyword; it is supported even when C99 keywords aren't visible.  This type qualifier is used as an optimization hint.  Any object accessed through a restrict qualified pointer may only be accessed through that pointer and the compiler may assume that there will be no aliasing.

_Packed

Open Watcom C/C++ supports the _Packed keyword which is used when describing a structure.  If specified before the struct keyword, the compiler will force the structure to be packed (no alignment, no gaps) regardless of the setting of the command-line option or the #pragma controlling the alignment of members.

__cdecl

Open Watcom C/C++ supports the __cdecl keyword to describe C functions that are called using a special convention.

Notes:

1.	All symbols are preceded by an underscore character.

2.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The calling routine will remove the arguments from the stack.

3.	Floating-point values are returned in the same way as structures.  When a structure is returned, the called routine returns a pointer in register AX/EAX to the return value which is stored in the data segment (DGROUP).

4.	For the 16-bit compiler, registers AX, BX, CX and DX, and segment register ES are not saved and restored when a call is made.

5.	For the 32-bit compiler, registers EAX, ECX and EDX are not saved and restored when a call is made.

Open Watcom C/C++ predefines the macros cdecl , _cdecl , _Cdecl and SOMLINK (16-bit only) to be equivalent to the __cdecl keyword.

__pascal

Open Watcom C/C++ supports the __pascal keyword to describe Pascal functions that are called using a special convention described by a pragma in the "stddef.h" header file.

Open Watcom C/C++ predefines the macros pascal , _pascal and _Pascal to be equivalent to the __pascal keyword.

__fortran

Open Watcom C/C++ supports the __fortran keyword to describe functions that are called from FORTRAN.  It converts the name to uppercase letters and suppresses the "_" which is appended to the function name for certain calling conventions.

Open Watcom C/C++ predefines the macros fortran and _fortran to be equivalent to the __fortran keyword.

__interrupt

Open Watcom C/C++ supports the __interrupt keyword to describe a function that is an interrupt handler.

Example:

     #include <i86.h>

     void __interrupt int10( union INTPACK r )

     {

             .

             .

             .

     }

The code generator will emit instructions to save all registers.  The registers are saved on the stack in a specific order so that they may be referenced using the "INTPACK" union as shown in the DOS example above.  The code generator will emit instructions to establish addressability to the program's data segment since the DS segment register contents are unpredictable.  The function will return using an "IRET" (16-bit) or "IRETD" (32-bit) (interrupt return) instruction.

Open Watcom C/C++ predefines the macros interrupt and _interrupt to be equivalent to the __interrupt keyword.

__declspec( modifier )

Open Watcom C/C++ supports the __declspec keyword for compatibility with Microsoft C++.  The __declspec keyword is used to modify storage-class attributes of functions and/or data.  There are several modifiers that can be specified with the __declspec keyword:  thread , naked , dllimport , dllexport , __pragma( "string" ) , __cdecl , __pascal , __fortran , __stdcall , and __syscall .  These attributes are a property only of the declaration of the object or function to which they are applied.  Unlike the __near and __far keywords, which actually affect the type of object or function (in this case, 2- and 4-byte addresses), these storage-class attributes do not redefine the type attributes of the object itself.  The __pragma modifier is supported by Open Watcom C++ only.  The thread attribute affects data and objects only.  The naked , __pragma , __cdecl , __pascal , __fortran , __stdcall , and __syscall attributes affect functions only.  The dllimport and dllexport attributes affect functions, data, and objects.  For more information on the __declspec keyword, please see the section entitled The __declspec Keyword.

__export

Open Watcom C/C++ supports the __export keyword to describe functions and other object names that are to be exported from a Microsoft Windows DLL, OS/2 DLL, or Netware NLM.  See also the description of the "zu" option.

Example:

     void __export _Setcolor( int color )

     {

             .

             .

             .

     }

Open Watcom C/C++ predefines the macro _export to be equivalent to the __export keyword.

__loadds

Open Watcom C/C++ supports the __loadds keyword to describe functions that require specific loading of the DS register to establish addressability to the function's data segment.  This keyword is useful in describing a function that will be placed in a Microsoft Windows or OS/2 1.x Dynamic Link Library (DLL).  See also the description of the "nd" and "zu" options.

Example:

     void __export __loadds _Setcolor( int color )

     {

             .

             .

             .

     }

If the function in an OS/2 1.x Dynamic Link Library requires access to private data, the data segment register must be loaded with an appropriate value since it will contain the DS value of the calling application upon entry to the function.

Open Watcom C/C++ predefines the macro _loadds to be equivalent to the __loadds keyword.

__saveregs

Open Watcom C/C++ recognizes the __saveregs keyword which is an attribute used by C/C++ compilers to describe a function that must save and restore all registers.

Open Watcom C/C++ predefines the macro _saveregs to be equivalent to the __saveregs keyword.

__stdcall

(32-bit only) The __stdcall keyword may be used with function definitions, and indicates that the 32-bit Win32 calling convention is to be used.

Notes:

1.	All symbols are preceded by an underscore character.

2.	All C symbols (extern "C" symbols in C++) are suffixed by "@nnn" where "nnn" is the sum of the argument sizes (each size is rounded up to a multiple of 4 bytes so that char and short are size 4).  When the argument list contains "...", the "@nnn" suffix is omitted.

3.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The called routine will remove the arguments from the stack.

4.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.  Floating-point values are returned in 80x87 register ST(0).

5.	Registers EAX, ECX and EDX are not saved and restored when a call is made.

__syscall

(32-bit only) The __syscall keyword may be used with function definitions, and indicates that the calling convention used is compatible with functions provided by 32-bit OS/2.

Notes:

1.	Symbols names are not modified, that is, they are not adorned with leading or trailing underscores.

2.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The calling routine will remove the arguments from the stack.

3.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.  Floating-point values are returned in 80x87 register ST(0).

4.	Registers EAX, ECX and EDX are not saved and restored when a call is made.

Open Watcom C/C++ predefines the macros _syscall , _System , SOMLINK (32-bit only) and SOMDLINK (32-bit only) to be equivalent to the __syscall keyword.

__far16

(32-bit only) Open Watcom C/C++ recognizes the __far16 keyword which can be used to define far 16-bit (far16) pointers (16-bit selector with 16-bit offset) or far 16-bit function prototypes.  This keyword can be used under 32-bit OS/2 to call 16-bit functions from your 32-bit flat model program.  Integer arguments will automatically be converted to 16-bit integers, and 32-bit pointers will be converted to far16 pointers before calling a special thunking layer to transfer control to the 16-bit function.

Open Watcom C/C++ predefines the macros _far16 and _Far16 to be equivalent to the __far16 keyword.  This keyword is compatible with Microsoft C.

In the OS/2 operating system (version 2.0 or higher), the first 512 megabytes of the 4 gigabyte segment referenced by the DS register is divided into 8192 areas of 64K bytes each.  A far16 pointer consists of a 16-bit selector referring to one of the 64K byte areas, and a 16-bit offset into that area.

A pointer declared as,

     [type] __far16 *name;

defines an object that is a far16 pointer.  If such a pointer is accessed in the 32-bit environment, the compiler will generate the necessary code to convert between the far16 pointer and a "flat" 32-bit pointer.

For example, the declaration,

     char __far16 *bufptr;

declares the object bufptr to be a far16 pointer to char .

A function declared as,

     [type] __far16 func( [arg_list] );

declares a 16-bit function.  Any calls to such a function from the 32-bit environment will cause the compiler to convert any 32-bit pointer arguments to far16 pointers, and any int arguments from 32 bits to 16 bits.  (In the 16-bit environment, an object of type int is only 16 bits.) Any return value from the function will have its return value converted in an appropriate manner.

For example, the declaration,

     char * __far16 Scan( char *buffer, int len, short err );

declares the 16-bit function Scan.  When this function is called from the 32-bit environment, the buffer argument will be converted from a flat 32-bit pointer to a far16 pointer (which, in the 16-bit environment, would be declared as char __far *.  The len argument will be converted from a 32-bit integer to a 16-bit integer.  The err argument will be passed unchanged.  Upon returning, the far16 pointer (far pointer in the 16-bit environment) will be converted to a 32-bit pointer which describes the equivalent location in the 32-bit address space.

_Seg16

(32-bit only) Open Watcom C/C++ recognizes the _Seg16 keyword which has a similar but not identical function as the __far16 keyword described above.  This keyword is compatible with IBM C Set/2 and IBM VisualAge C++.

In the OS/2 operating system (version 2.0 or higher), the first 512 megabytes of the 4 gigabyte segment referenced by the DS register is divided into 8192 areas of 64K bytes each.  A far16 pointer consists of a 16-bit selector referring to one of the 64K byte areas, and a 16-bit offset into that area.

Note that _Seg16 is not interchangeable with __far16 .

A pointer declared as,

     [type] * _Seg16 name;

defines an object that is a far16 pointer.  Note that the _Seg16 appears on the right side of the * which is opposite to the __far16 keyword described above.

For example,

     char * _Seg16 bufptr;

declares the object bufptr to be a far16 pointer to char (the same as above).

The _Seg16 keyword may not be used to describe a 16-bit function.  A #pragma directive must be used instead.  A function declared as,

     [type] * _Seg16 func( [parm_list] );

declares a 32-bit function that returns a far16 pointer.

For example, the declaration,

     char * _Seg16 Scan( char * buffer, int len, short err );

declares the 32-bit function Scan.  No conversion of the argument list will take place.  The return value is a far16 pointer.

__pragma

Open Watcom C++ supports the __pragma keyword to support in-lining of member functions.  The __pragma keyword must be followed by parentheses containing a string that names an auxiliary pragma.  Here is a simplified example showing usage and syntax.

Example:

     #pragma aux fast_mul = \

         "imul eax,edx" \

         parm caller [eax] [edx] \

         value struct;

     struct fixed {

         unsigned v;

     };

     fixed __pragma( "fast_mul") operator *( fixed, fixed );

     fixed two = { 2 };

     fixed three = { 3 };

     fixed foo()

     {

         return two * three;

     }

See the chapters entitled 16-bit Pragmas and 32-bit Pragmas for more information on pragmas.

__int8

Open Watcom C/C++ supports the __int8 keyword to define 8-bit integer data objects.

Example:

     static __int8 smallInt;

Also supported are signed and unsigned 8-bit integer constants.  The __int8 data type will be unsigned by default if the compiler is invoked with the -j switch.

__int16

Open Watcom C/C++ supports the __int16 keyword to define 16-bit integer data objects.

Example:

     static __int16 shortInt;

Also supported are signed and unsigned 16-bit integer constants.

__int32

Open Watcom C/C++ supports the __int32 keyword to define 32-bit integer data objects.

Example:

     static __int32 longInt;

Also supported are signed and unsigned 32-bit integer constants.

__int64

Open Watcom C/C++ supports the __int64 keyword to define 64-bit integer data objects.

Example:

     static __int64 bigInt;

Also supported are signed and unsigned 64-bit integer constants.

signed __int64

Use the "i64" suffix for a signed 64-bit integer constant.

Example:

     12345i64

     12345I64

unsigned __int64

Use the "ui64" suffix for an unsigned 64-bit integer constant.

Example:

     12345Ui64

     12345uI64

The run-time library supports formatting of __int64 items (see the description of the printf library function).

Example:

     #include <stdio.h>

     #include <limits.h>

     void main()

     {

         __int64 bigint;

         __int64 bigint2;

         bigint2 = 8I64 * (LONG_MAX + 1I64);

         for( bigint = 0;

              bigint <= bigint2;

              bigint += bigint2 / 16 ) {

             printf( "Hello world %Ld\n", bigint );

         }

     }

Restrictions

switch

An __int64 expression cannot be used in a switch statement.

bit fields

More than 32 bits in a 64-bit bitfield is not supported.


Based Pointers

Near pointers are generally the most efficient type of pointer because they are small, and the compiler can assume knowledge about what segment of the computer's memory the pointer (offset) refers to.  Far pointers are the most flexible because they allow the programmer to access any part of the computer's memory, without limitation to a particular segment.  However, far pointers are bigger and slower because of the additional flexibility.

Based pointers are a compromise between the efficiency of near pointers and the flexibility of far pointers.  With based pointers, the programmer takes responsibility to tell the compiler which segment a near pointer (offset) belongs to, but may still access segments of the computer's memory outside of the normal data segment (DGROUP).  The result is a pointer type which is as small as and almost as efficient as a near pointer, but with most of the flexibility of a far pointer.

An object declared as a based pointer falls into one of the following categories:

•	the based pointer is in the segment described by another object,

•	the based pointer, used as a pointer to another object of the same type (as in a linked list), refers to the same segment,

•	the based pointer is an offset to no particular segment, and must be combined explicitly with a segment value to produce a valid pointer.

To support based pointers, the following keywords are provided:

     __based

     __segment

     __segname

     __self

The following operator is also provided:

     :>

These keywords and operator are described in the following sections.

Two macros, defined in malloc.h, are also provided:

     _NULLSEG

     _NULLOFF

They are used in a manner similar to NULL , but are used with objects declared as __segment and __based respectively.


Segment Constant Based Pointers and Objects

A segment constant based pointer or object has its segment value based on a specific, named segment.  A segment constant based object is specified as:

     [type] __based( __segname( "segment" ) ) object_name;

and a segment constant based pointer is specified as:

     [type] __based( __segname( "segment" ) ) *object-name;

where segment is the name of the segment in which the pointer or object is based.  As shown above, the segment name is always specified as a string.  There are four special segment names recognized by the compiler:

     "_CODE"

     "_CONST"

     "_DATA"

     "_STACK"

The "_CODE" segment is the default code segment.  The "_CONST" segment is the segment containing constant values.  The "_DATA" segment is the default data segment.  The "_STACK" segment is the segment containing the stack.  If the segment name is not one of the recognized names, then a segment will be created with that name.  If a segment constant based object is being defined, then it will be placed in the named segment.  If a segment constant based pointer is being defined, then it can point at objects in the named segment.

The following examples illustrate segment constant based pointers and objects.

Example:

     int __based( __segname( "_CODE" ) )  ival = 3;

     int __based( __segname( "_CODE" ) ) *iptr;

ival is an object that resides in the default code segment.  iptr is an object that resides in the data segment (the usual place for data objects), but points at an integer which resides in the default code segment.  iptr is suitable for pointing at ival.

Example:

     char __based( __segname( "GOODTHINGS" ) ) thing;

thing is an object which resides in the segment GOODTHINGS, which will be created if it does not already exist.  (The creation of segments is done by the linker, and is a method of grouping objects and functions.  Nothing is implicitly created during the execution of the program.)


Segment Object Based Pointers

A segment object based pointer derives its segment value from another named object.  A segment object based pointer is specified as follows:

     [type] __based( segment ) *name;

where segment is an object defined as type __segment .

An object of type __segment may contain a segment value.  Such an object is particularly designed for use with segment object based pointers.

The following example illustrates a segment object based pointer:

Example:

     __segment            seg;

     char __based( seg ) *cptr;

The object seg contains only a segment value.  Whenever the object cptr is used to point to a character, the actual pointer value will be made up of the segment value found in seg and the offset value found in cptr.  The object seg might be assigned values such as the following:

•	a constant value (e.g., the segment containing screen memory),

•	the result of the library function _bheapseg ,

•	the segment portion of another pointer value, by casting it to the type __segment .


Void Based Pointers

A void based pointer must be explicitly combined with a segment value to produce a reference to a memory location.  A void based pointer does not infer its segment value from another object.  The :> (base) operator is used to combine a segment value and a void based pointer.

For example, on a personal computer running DOS with a color monitor, the screen memory begins at segment 0xB800, offset 0.  In a video text mode, to examine the first character currently displayed on the screen, the following code could be used:

Example:

     extern void main()

     {

         __segment             screen;

         char __based( void ) *scrptr;

         screen = 0xB800;

         scrptr = 0;

         printf( "Top left character is '%c'.\n",

                 *(screen:>scrptr) );

     }

The general form of the :> operator is:

     segment :> offset

where segment is an expression of type __segment , and offset is an expression of type __based( void ) *.


Self Based Pointers

A self based pointer infers its segment value from itself.  It is particularly useful for structures such as linked lists, where all of the list elements are in the same segment.  A self based pointer pointing to one element may be used to access the next element, and the compiler will use the same segment as the original pointer.

The following example illustrates a function which will print the values stored in the last two members of a linked list:

Example:

     struct a {

         struct a __based( __self ) *next;

         int                         number;

     };

     extern void PrintLastTwo( struct a far *list )

     {

       __segment                seg;

       struct a __based( seg ) *aptr;

       seg  = FP_SEG( list );

       aptr = FP_OFF( list );

       for( ; aptr != _NULLOFF; aptr = aptr->next ) {

         if( aptr->next == _NULLOFF ) {

           printf( "Last item is %d\n",

                   aptr->number );

         } else if( aptr->next->next == _NULLOFF ) {

           printf( "Second last item is %d\n",

                   aptr->number );

         }

       }

     }

The argument to the function PrintLastTwo is a far pointer, pointing to a linked list structure anywhere in memory.  It is assumed that all members of a particular linked list of this type reside in the same segment of the computer's memory.  (Another instance of the linked list might reside entirely in a different segment.) The object seg is given the segment portion of the far pointer.  The object aptr is given the offset portion, and is described as being based in the segment stored in seg.

The expression aptr->next refers to the next member of the structure stored in memory at the offset stored in aptr and the segment implied by aptr, which is the value stored in seg.  So far, the behavior is no different than if next had been declared as,

     struct a *next;

The expression aptr->next->next illustrates the difference of using a self based pointer.  The first part of the expression ( aptr->next) occurs as described above.  However, using the result to point to the next member occurs by using the offset value found in the next member and combining it with the segment value of the pointer used to get to that member, which is still the segment implied by aptr, which is the value stored in seg.  If next had not been declared using __based( __self ), then the second pointing operation would refer to the offset value found in the next member, but with the default data segment (DGROUP), which may or may not be the same segment as stored in seg.


The __declspec Keyword

Open Watcom C/C++ supports the __declspec keyword for compatibility with Microsoft C++.  The __declspec keyword is used to modify storage-class attributes of functions and/or data.

__declspec( thread )

is used to define thread local storage (TLS).  TLS is the mechanism by which each thread in a multithreaded process allocates storage for thread-specific data.  In standard multithreaded programs, data is shared among all threads of a given process, whereas thread local storage is the mechanism for allocating per-thread data.

Example:

     __declspec(thread) static int tls_data = 0;

The following rules apply to the use of the thread attribute.

•	The thread attribute can be used with data and objects only.

•	You can specify the thread attribute only on data items with static storage duration.  This includes global data objects (both static and extern ), local static objects, and static data members of classes.  Automatic data objects cannot be declared with the thread attribute.  The following example illustrates this error:

Example:

     #define TLS __declspec( thread )

     void func1()

     {

         TLS int tls_data;           // Wrong!

     }

     int func2( TLS int tls_data )   // Wrong!

     {

         return tls_data;

     }

•	The thread attribute must be used for both the declaration and the definition of a thread local object, whether the declaration and definition occur in the same file or separate files.  The following example illustrates this error:

Example:

     #define TLS __declspec( thread )

     extern int tls_data;    // This generates an error, because the

     TLS    int tls_data;    // declaration and the definition differ.

•	Classes cannot use the thread attribute.  However, you can instantiate class objects with the thread attribute, as long as the objects do not need to be constructed or destructed.  For example, the following code generates an error:

Example:

     #define TLS __declspec( thread )

     TLS class A     // Wrong! Classes are not objects

     {

         // Code

     };

     A AObject;

Because the declaration of objects that use the thread attribute is permitted, these two examples are semantically equivalent:

Example:

     #define TLS __declspec( thread )

     TLS class B

     {

         // Code

     } BObject;      // Okay! BObject declared thread local.

     class C

     {

         // Code

     };

     TLS C CObject;  // Okay! CObject declared thread local.

•	Standard C permits initialization of an object or variable with an expression involving a reference to itself, but only for objects of non-static extent.  Although C++ normally permits such dynamic initialization of an object with an expression involving a reference to itself, this type of initialization is not permitted with thread local objects.

Example:

     #define TLS  __declspec( thread )

     TLS int tls_i = tls_i;            // C and C++ error

     int j = j;                        // Okay in C++; C error

     TLS int tls_k = sizeof( tls_k );  // Okay in C and C++

Note that a sizeof expression that includes the object being initialized does not constitute a reference to itself and is allowed in C and C++.

__declspec( naked )

indicates to the code generator that no prologue or epilogue sequence is to be generated for a function.  Any statements other than "_asm" directives or auxiliary pragmas are not compiled.  _asm Essentially, the compiler will emit a "label" with the specified function name into the code.

Example:

     #include <stdio.h>

     int __declspec( naked ) foo( int x )

     {

         _asm {

     #if defined(__386__)

             inc eax

     #else

             inc ax

     #endif

             ret

         }

     }

     void main()

     {

         printf( "%d\n", foo( 1 ) );

     }

The following rules apply to the use of the naked attribute.

•	The naked attribute cannot be used in a data declaration.  The following declaration would be flagged in error.

Example:

     __declspec(naked) static int data_object = 0;

__declspec( dllimport )

is used to declare functions, data and objects imported from a DLL.

Example:

     #define DLLImport __declspec(dllimport)

     DLLImport void dll_func();

     DLLImport int  dll_data;

Functions, data and objects are exported from a DLL by use of __declspec(dllexport) ct , the __export keyword (for which __declspec(dllexport) is the replacement), or through linker "EXPORT" directives.

Note:  When calling functions imported from other modules, it is not strictly necessary to use the __declspec(dllimport) modifier to declare the functions.  This modifier however must always be used when importing data or objects to ensure correct behavior.

__declspec( dllexport )

is used to declare functions, data and objects exported from a DLL.  Declaring functions as dllexport eliminates the need for linker "EXPORT" directives.  The __declspec(dllexport) attribute is a replacement for the __export keyword.

__declspec( __pragma( "string" ) )

is used to declare functions which adhere to the conventions described by the pragma identified by "string".

Example:

     #include <stdio.h>

     #pragma aux my_stdcall "_*" \

             parm routine [] \

             value struct struct caller [] \

             modify [eax ecx edx];

     struct list {

         struct list *next;

         int         value;

         float       flt_value;

     };

     #define STDCALL __declspec( __pragma("my_stdcall") )

     STDCALL struct list foo( int x, char *y, double z );

     void main()

     {

         int a = 1;

         char *b = "Hello there";

         double c = 3.1415926;

         struct list t;

         t = foo( a, b, c );

         printf( "%d\n", t.value );

     }

     struct list foo( int x, char *y, double z )

     {

         struct list tmp;

         printf( "%s\n", y );

         tmp.next = NULL;

         tmp.value = x;

         tmp.flt_value = z;

         return( tmp );

     }

It is also possible to modify the calling convention of all methods of a class or just an individual method.

Example:

     #pragma aux my_thiscall "_*" \

             parm routine [ecx] \

             value struct struct caller [] \

             modify [eax ecx edx];

     #define THISCALL __declspec( __pragma("my_thiscall") )

     class THISCALL IWatcom: public IUnknown{

         virtual int method_a( void ) = 0;

         virtual int method_b( void ) = 0;

         virtual int __cdecl method_c( void ) = 0;

     };

In this example, any calls generated to the virtual methods 'method_a' or 'method_b' will use the THISCALL ( my_thiscall ) calling convention.  Calls generated to 'method_c' will use the prefefined __cdecl calling convention.

It is also possible to forward define the class with modifiers for occasions where you do not want to change original source code.

Example:

     #pragma aux my_thiscall "_*" \

             parm routine [ecx] \

             value struct struct caller [] \

             modify [eax ecx edx];

     #define THISCALL __declspec( __pragma("my_thiscall") )

     class THISCALL IWatcom;

     class IWatcom: public IUnknown{

         virtual int method_a( void ) = 0;

         virtual int method_b( void ) = 0;

         virtual int __cdecl method_c( void ) = 0;

     };

The __pragma modifier is supported by Open Watcom C++ only.

__declspec( __cdecl )

is used to declare functions which conform to the Microsoft compiler calling convention.

__declspec( __pascal )

is used to declare functions which conform to the OS/2 1.x and Windows 3.x calling convention.

__declspec( __fortran )

is used to declare functions which conform to the __fortran calling convention.

Example:

     #include <stdio.h>

     #define DLLFunc __declspec(dllimport __fortran)

     #define DLLData __declspec(dllimport)

     #ifdef __cplusplus

     extern "C" {

     #endif

     DLLFunc int  dll_func( int, int, int );

     DLLData int  dll_data;

     #ifdef __cplusplus

     };

     #endif

     void main()

     {

       printf( "%d %d\n", dll_func( 1,2,3 ), dll_data );

     }

__declspec( __stdcall )

is used to declare functions which conform to the 32-bit Win32 "standard" calling convention.

Example:

     #include <stdio.h>

     #define DLLFunc __declspec(dllimport __stdcall)

     #define DLLData __declspec(dllimport)

     DLLFunc int  dll_func( int, int, int );

     DLLData int  dll_data;

     void main()

     {

       printf( "%d %d\n", dll_func( 1,2,3 ), dll_data );

     }

__declspec( __syscall )

is used to declare functions which conform to the 32-bit OS/2 __syscall calling convention.


The Open Watcom Code Generator

The Open Watcom Code Generator performs such optimizations as common subexpression elimination, global flow analysis, and so on.

In some cases, the code generator can do a better job of optimizing code if it could utilize more memory.  This is indicated when a

     Not enough memory to optimize procedure 'xxxx'

message appears on the screen as the source program is compiled.  In such an event, you may wish to make more memory available to the code generator.

A special environment variable may be used to obtain memory usage information or set memory usage limits on the code generator.  The WCGMEMORY environment variable may be used to request a report of the amount of memory used by the compiler's code generator for its work area.

Example:

     C>set WCGMEMORY=?

When the memory amount is "?" then the code generator will report how much memory was used to generate the code.

It may also be used to instruct the compiler's code generator to allocate a fixed amount of memory for a work area.

Example:

     C>set WCGMEMORY=128

When the memory amount is "nnn" then exactly "nnnK" bytes will be used.  In the above example, 128K bytes is requested.  If less than "nnnK" is available then the compiler will quit with a fatal error message.  If more than "nnnK" is available then only "nnnK" will be used.

There are two reasons why this second feature may be quite useful.  In general, the more memory available to the code generator, the more optimal code it will generate.  Thus, for two personal computers with different amounts of memory, the code generator may produce different (although correct) object code.  If you have a software quality assurance requirement that the same results (i.e., code) be produced on two different machines then you should use this feature.  To generate identical code on two personal computers with different memory configurations, you must ensure that the WCGMEMORY environment variable is set identically on both machines.

The second reason where this feature is useful is on virtual memory paging systems (e.g., OS/2) where an unlimited amount of memory can be used by the code generator.  If a very large module is being compiled, it may take a very long time to compile it.  The code generator will continue to allocate more and more memory and cause an excessive amount of paging.  By restricting the amount of memory that the code generator can use, you can reduce the amount of time required to compile a routine.


Precompiled Headers

Open Watcom C/C++ supports the use of precompiled headers to decrease the time required to compile several source files that include the same header file.


When to Precompile Header Files

Using precompiled headers reduces compilation time when:

•	You always use a large body of code that changes infrequently.

•	Your program comprises multiple modules, all of which use the same first include file and the same compilation options.  In this case, the first include file along with all the files that it includes can be precompiled into one precompiled header.

Because the compiler only uses the first include file to create a precompiled header, you may want to create a master or global header file that includes all the other header files that you wish to have precompiled.  Then all source files should include this master header file as the first #include in the source file.  Even if you don't use a master header file, you can benefit from using precompiled headers for Windows programs by using #include <windows.h> as the first include file, or by using #include <afxwin.h> as the first include file for MFC applications.

The first compilation - the one that creates the precompiled header file - takes a bit longer than subsequent compilations.  Subsequent compilations can proceed more quickly by including the precompiled header.

You can precompile C and C++ programs.  In C++ programming, it is common practice to separate class interface information into header files which can later be included in programs that use the class.  By precompiling these headers, you can reduce the time a program takes to compile.

  Note:  Although you can use only one precompiled header (.PCH) file per source file, you can use multiple .PCH files in a project.


Creating and Using Precompiled Headers

Precompiled code is stored in a file called a precompiled header when you use the precompiled header option ( /fh or /fhq) on the command line.  The /fh option causes the compiler to either create a precompiled header or use the precompiled header if it already exists.  The /fhq option is similar but prevents the compiler from issuing informational or warning messages about precompiled header files.  The default name of the precompiled header file is one of WCC.PCH, WCC386.PCH, WPP.PCH, or WPP386.PCH (depending on the compiler used).  You can also control the name of the precompiled header that is created or used with the /fh=filename or /fhq=filename ("specify precompiled header filename") options.

Example:

     /fh=projectx.pch

     /fhq=projectx.pch


The "/fh[q]" (Precompiled Header) Option

The /fh option instructs the compiler to use a precompiled header file with a default name of WCC.PCH, WCC386.PCH, WPP.PCH, or WPP386.PCH (depending on the compiler used) if it exists or to create one if it does not.  The file is created in the current directory.  You can use the /fh=filename option to change the default name (and placement) of the precompiled header.  Add the letter "q" (for "quiet") to the option name to prevent the compiler from displaying precompiled header activity information.

The following command line uses the /fh option to create a precompiled header.

Example:

     wpp /fh myprog.cpp

     wpp386 /fh myprog.cpp

The following command line creates a precompiled header named myprog.pch and places it in the \projpch directory.

Example:

     wpp /fh=\projpch\myprog.pch myprog.cpp

     wpp386 /fh=\projpch\myprog.pch myprog.cpp

The precompiled header is created and/or used when the compiler encounters the first #include directive that occurs in the source file.  In a subsequent compilation, the compiler performs a consistency check to see if it can use an existing precompiled header.  If the consistency check fails then the compiler discards the existing precompiled header and builds a new one.

The /fhq form of the precompiled header option prevents the compiler from issuing warning or informational messages about precompiled header files.  For example, if you change a header file, the compiler will tell you that it changed and that it must regenerate the precompiled header file.  If you specify /fhq then the compiler just generates the new precompiled header file without displaying a message.


Consistency Rules for Precompiled Headers

If a precompiled header file exists (either the default file or one specified by /fh=filename), it is compared to the current compilation for consistency.  A new precompiled header file is created and the new file overwrites the old unless the following requirements are met:

•	The current compiler options must match those specified when the precompiled header was created.

•	The current working directory must match that specified when the precompiled header was created.

•	The name of the first #include directive must match the one that was specified when the precompiled header was created.

•	All macros defined prior to the first #include directive must have the same values as the macros defined when the precompiled header was created.  A sequence of #define directives need not occur in exactly the same order because there are no semantic order dependencies for #define directives.

•	The value and order of include paths specified on the command line with /i options must match those specified when the precompiled header was created.

•	The time stamps of all the header files (all files specified with #include directives) used to build the precompiled header must match those that existed when the precompiled header was created.


The Open Watcom C/C++ Libraries

The Open Watcom C/C++ library routines are described in the Open Watcom C Library Reference manual, and the Open Watcom C++ Class Library Reference manual.


Open Watcom C/C++ Library Directory Structure

Since Open Watcom C/C++ supports both 16-bit and 32-bit application development, libraries are grouped under two major subdirectories.  The LIB286 directory is used to contain libraries for 16-bit application development.  The LIB386 directory is used to contain libraries for 32-bit application development.

For 16-bit application development, the Intel x86 processor-dependent libraries are placed under the \WATCOM\LIB286 directory.

For 32-bit application development, the Intel 386 and upward-compatible processor-dependent libraries are placed under the \WATCOM\LIB386 directory.

Since Open Watcom C/C++ also supports several operating systems, including DOS, OS/2, Windows 3.x and Windows NT, system-dependent libraries are grouped under different directories underneath the processor-dependent directories.

For DOS applications, the system-dependent libraries are placed in \WATCOM\LIB286\DOS (16-bit applications) and \WATCOM\LIB386\DOS (32-bit applications).

For OS/2 applications, the system-dependent libraries are placed in \WATCOM\LIB286\OS2 (16-bit applications) and \WATCOM\LIB386\OS2 (32-bit applications).

For Microsoft Windows applications, the system-dependent libraries are placed in \WATCOM\LIB286\WIN (16-bit applications) and \WATCOM\LIB386\WIN (32-bit applications).

For Microsoft Windows NT applications, the system-dependent libraries are placed in \WATCOM\LIB386\NT (32-bit applications).

For Novell NetWare 386 applications, the system-dependent libraries are placed in \WATCOM\LIB386\NETWARE (32-bit applications).

                       \watcom

                          |

              .-----------+----------------.

              |                            |

           lib286                       lib386

              |                            |

      .-------+-------.    .-------.-------+-------.-------.

      |       |       |    |       |       |       |       |

     dos     os2     win  dos     os2     win      nt   netware

      |       |       |    |       |       |       |       |


Open Watcom C/C++ C Libraries

Due to the many code generation strategies possible in the 80x86 family of processors, a number of versions of the libraries are provided.  You must use the libraries which coincide with the particular architecture, operating system, and code generation strategy or model that you have selected.  For the type of code generation strategy or model that you intend to use, refer to the description of the "m?" memory model compiler option.  The various code models supported by Open Watcom C/C++ are described in the chapters entitled 16-bit Memory Models and 32-bit Memory Models.

We have selected a simple naming convention for the libraries that are provided with Open Watcom C/C++.  Letters are affixed to the file name to indicate the particular strategy with which the modules in the library have been compiled.

16-bit only

S

denotes a version of the Open Watcom C/C++ libraries which have been compiled for the "small" memory model (small code, small data).

M

denotes a version of the Open Watcom C/C++ libraries which have been compiled for the "medium" memory model (big code, small data).

C

denotes a version of the Open Watcom C/C++ libraries which have been compiled for the "compact" memory model (small code, big data).

L

denotes a version of the Open Watcom C/C++ libraries which have been compiled for the "large" memory model (big code, big data).

H

denotes a version of the Open Watcom C/C++ libraries which have been compiled for the "huge" memory model (big code, huge data).

MT

denotes a version of the Open Watcom C/C++ libraries which may be used with OS/2 multi-threaded applications.

DL

denotes a version of the Open Watcom C/C++ libraries which may be used when creating an OS/2 Dynamic Link Library.

32-bit only

3R

denotes a version of the Open Watcom C/C++ libraries that will be used by programs which have been compiled for the "flat/small" memory models using the "3r", "4r", "5r" or "6r" option.

3S

denotes a version of the Open Watcom C/C++ libraries that will be used by programs which have been compiled for the "flat/small" memory models using the "3s", "4s", "5s" or "6s" option.

The Open Watcom C/C++ 16-bit libraries are listed below by directory.

Under \WATCOM\LIB286\DOS

     CLIBS.LIB    (DOS small model support)

     CLIBM.LIB    (DOS medium model support)

     CLIBC.LIB    (DOS compact model support)

     CLIBL.LIB    (DOS large model support)

     CLIBH.LIB    (DOS huge model support)

     GRAPH.LIB    (model independent, DOS graphics support)

     DOSLFNS.LIB  (DOS LFN small model support)

     DOSLFNM.LIB  (DOS LFN medium model support)

     DOSLFNC.LIB  (DOS LFN compact model support)

     DOSLFNL.LIB  (DOS LFN large model support)

     DOSLFNH.LIB  (DOS LFN huge model support)

Under \WATCOM\LIB286\OS2

     CLIBS.LIB    (OS/2 small model support)

     CLIBM.LIB    (OS/2 medium model support)

     CLIBC.LIB    (OS/2 compact model support)

     CLIBL.LIB    (OS/2 large model support)

     CLIBH.LIB    (OS/2 huge model support)

     CLIBMTL.LIB  (OS/2 multi-thread, large model support)

     CLIBDLL.LIB  (OS/2 DLL, large model support)

     DOSPMS.LIB   (Phar Lap 286 PM small model support)

     DOSPMM.LIB   (Phar Lap 286 PM medium model support)

     DOSPMC.LIB   (Phar Lap 286 PM compact model support)

     DOSPML.LIB   (Phar Lap 286 PM large model support)

     DOSPMH.LIB   (Phar Lap 286 PM huge model support)

Under \WATCOM\LIB286\WIN

     CLIBS.LIB    (Windows small model support)

     CLIBM.LIB    (Windows medium model support)

     CLIBC.LIB    (Windows compact model support)

     CLIBL.LIB    (Windows large model support)

     WINDOWS.LIB  (Windows API library)

The Open Watcom C/C++ 32-bit libraries are listed below by directory.

Under \WATCOM\LIB386\DOS

     CLIB3R.LIB   (flat/small models, "3r", "4r", "5r" or "6r" option)

     CLIB3S.LIB   (flat/small models, "3s", "4s", "5s" or "6s" option)

     GRAPH.LIB    (flat/small models, DOS graphics support)

     DOSLFN3R.LIB (flat/small models, DOS LFN support,

                                      "3r", "4r", "5r" or "6r" option)

     DOSLFN3S.LIB (flat/small models, DOS LFN support,

                                      "3s", "4s", "5s" or "6s" option)

The graphics library GRAPH.LIB is independent of the argument passing conventions.

Under \WATCOM\LIB386\OS2

     CLIB3R.LIB   (flat/small models, "3r", "4r", "5r" or "6r" option)

     CLIB3S.LIB   (flat/small models, "3s", "4s", "5s" or "6s" option)

Under \WATCOM\LIB386\WIN

     CLIB3R.LIB   (flat/small models, "3r", "4r", "5r" or "6r" option)

     CLIB3S.LIB   (flat/small models, "3s", "4s", "5s" or "6s" option)

     WIN386.LIB   (32-bit Windows API)

Under \WATCOM\LIB386\NT

     CLIB3R.LIB   (flat/small models, "3r", "4r", "5r" or "6r" option)

     CLIB3S.LIB   (flat/small models, "3s", "4s", "5s" or "6s" option)


Open Watcom C/C++ Class Libraries

The Open Watcom C/C++ Class Library routines are described in the Open Watcom C++ Class Library Reference manual.

The Open Watcom C++ 16-bit Class Libraries are listed below.

Under \WATCOM\LIB286

         (iostream and string class libraries)

     PLIBS.LIB    (small model support)

     PLIBM.LIB    (medium model support)

     PLIBC.LIB    (compact model support)

     PLIBL.LIB    (large model support)

     PLIBH.LIB    (huge model support)

     PLIBMTL.LIB  (OS/2 multi-thread, large model support)

     PLIBDLL.LIB  (OS/2 DLL, large model support)

         (complex class library for "fpc" option)

     CPLXS.LIB    (small model support)

     CPLXM.LIB    (medium model support)

     CPLXC.LIB    (compact model support)

     CPLXL.LIB    (large model support)

     CPLXH.LIB    (huge model support)

         (complex class library for "fpi..." options)

     CPLX7S.LIB   (small model support)

     CPLX7M.LIB   (medium model support)

     CPLX7C.LIB   (compact model support)

     CPLX7L.LIB   (large model support)

     CPLX7H.LIB   (huge model support)

These libraries are independent of the operating system (except those designated for OS/2).  The "7" designates a library compiled with the "7" option.

The Open Watcom C++ 32-bit Class Libraries are listed below.

Under \WATCOM\LIB386

         (iostream and string class libraries)

     PLIB3R.LIB   (flat models, "3r", "4r", "5r" or "6r" option)

     PLIB3S.LIB   (flat models, "3s", "4s", "5s" or "6s" option)

     PLIBMT3R.LIB (multi-thread library for OS/2 and Windows NT)

     PLIBMT3S.LIB (multi-thread library for OS/2 and Windows NT)

         (complex class library for "fpc" option)

     CPLX3R.LIB   (flat models, "3r", "4r", "5r" or "6r" option)

     CPLX3S.LIB   (flat models, "3s", "4s", "5s" or "6s" option)

         (complex class library for "fpi..." options)

     CPLX73R.LIB  (flat models, "3r", "4r", "5r" or "6r" option)

     CPLX73S.LIB  (flat models, "3s", "4s", "5s" or "6s" option)

These libraries are independent of the operating system (except those designated for OS/2 and Windows NT).  The "3R" and "3S" suffixes refer to the argument passing convention used.  The "7" designates a library compiled with the "7" option.


Open Watcom C/C++ Math Libraries

In general, a Math library is required when floating-point computations are included in the application.  The Math libraries are operating-system independent.

For the 286 architecture, the Math libraries are placed under the \WATCOM\LIB286 directory.

For the 386 architecture, the Math libraries are placed under the \WATCOM\LIB386 directory.

An 80x87 emulator library, emu87.lib, is also provided which is both operating-system and architecture dependent.

The following situations indicate that one of the Math libraries should be included when linking the application.

1.	When one or more of the functions described in the math.h header file is referenced, then a Math library must be included.

2.	If an application is linked and the message

     "_fltused_ is an undefined reference"

appears, then a Math library must be included.

3.	(16-bit only) If an application is linked and the message

     "__init_87_emulator is an undefined reference"

appears, then one of the modules in the application was compiled with one of the "fpi", "fpi87", "fp2", "fp3" or "fp5" options.  If the "fpi" option was used, the 80x87 emulator library ( emu87.lib ) or the 80x87 fixup library ( noemu87.lib ) should be included when linking the application.

If the "fpi87" option was used, the 80x87 fixup library noemu87.lib should be included when linking the application.

The 80x87 emulator is contained in emu87.lib.  Use noemu87.lib in place of emu87.lib when the emulator is not wanted.

4.	(32-bit only) If an application is linked and the message

     "__init_387_emulator is an undefined reference"

appears, then one of the modules in the application was compiled with one of the "fpi", "fpi87", "fp2", "fp3" or "fp5" options.  If the "fpi" option was used, the 80x87 emulator library ( emu387.lib) should be included when linking the application.

If the "fpi87" option was used, the empty 80x87 emulator library noemu387.lib should be included when linking the application.

The 80x87 emulator is contained in emu387.lib.  Use noemu387.lib in place of emu387.lib when the emulator is not wanted.

Normally, the compiler and linker will automatically take care of this.  Simply ensure that the WATCOM environment variable includes the location of the Open Watcom C/C++ libraries.


Open Watcom C/C++ 80x87 Math Libraries

One of the following Math libraries must be used if any of the modules of your application were compiled with one of the Open Watcom C/C++ "fpi", "fpi87", "fp2", "fp3" or "fp5" options and your application requires floating-point support for the reasons given above.

16-bit libraries:

     MATH87S.LIB (small model)

     MATH87M.LIB (medium model)

     MATH87C.LIB (compact model)

     MATH87L.LIB (large model)

     MATH87H.LIB (huge model)

     NOEMU87.LIB

     DOS\EMU87.LIB (DOS dependent)

     OS2\EMU87.LIB (OS/2 dependent)

     WIN\EMU87.LIB (Windows dependent)

     WIN\MATH87C.LIB (Windows dependent)

     WIN\MATH87L.LIB (Windows dependent)

32-bit libraries:

     MATH387R.LIB (flat/small models, "3r", "4r", "5r" or "6r" option)

     MATH387S.LIB (flat/small models, "3s", "4s", "5s" or "6s" option)

     DOS\EMU387.LIB (DOS dependent)

     WIN\EMU387.LIB (Windows dependent)

     OS2\EMU387.LIB (OS/2 dependent)

     NT\EMU387.LIB (Windows NT dependent)

The "fpi" option causes an 80x87 numeric data processor emulator to be linked into your application in addition to any 80x87 math routines that were referenced.  This emulator will decode and emulate 80x87 instructions when an 80x87 is not present in the system or if the environment variable NO87 has been set (this variable is described below).

For 32-bit Open Watcom Windows-extender applications or 32-bit applications run in Windows 3.1 DOS boxes, you must also include the WEMU387.386 file in the [386enh] section of the SYSTEM.INI file.

Example:

     device=C:\WATCOM\binw\wemu387.386

Note that the WDEBUG.386 file which is installed by the Open Watcom Installation software contains the emulation support found in the WEMU387.386 file.

When the "fpi87" option is used exclusively, the emulator is not included.  In this case, the application must be run on personal computer systems equipped with the numeric data processor.


Open Watcom C/C++ Alternate Math Libraries

One of the following Math libraries must be used if any of the modules of your application were compiled with the Open Watcom C/C++ "fpc" option and your application requires floating-point support for the reasons given above.  The following Math libraries include support for floating-point which is done out-of-line through run-time calls.

16-bit libraries:

     MATHS.LIB (small model)

     MATHM.LIB (medium model)

     MATHC.LIB (compact model)

     MATHL.LIB (large model)

     MATHH.LIB (huge model)

     WIN\MATHC.LIB (Windows dependent)

     WIN\MATHL.LIB (Windows dependent)

32-bit libraries:

     MATH3R.LIB (flat/small models, "3r", "4r", "5r" or "6r" option)

     MATH3S.LIB (flat/small models, "3s", "4s", "5s" or "6s" option)

Applications which are linked with one of these libraries do not require a numeric data processor for floating-point operations.  If one is present in the system, it will be used; otherwise floating-point operations are simulated in software.  The numeric data processor will not be used if the environment variable NO87 has been set (this variable is described below).


The NO87 Environment Variable

If you have a numeric data processor (math coprocessor) in your system but you wish to test a version of your application that will use floating-point emulation ("fpi" option) or simulation ("fpc" option), you can define the NO87 environment variable.

(16-bit only) The application must be compiled using the "fpc" (floating-point calls) option and linked with the appropriate math?.lib library or the "fpi" option (default) and linked with the appropriate math87?.lib and emu87.lib libraries.

(32-bit only) The application must be compiled using the "fpc" (floating-point calls) option and linked with the appropriate math3?.lib library or the "fpi" option (default) and linked with the appropriate math387?.lib library.

Using the "SET" command, define the environment variable as follows:

     C>SET NO87=1

Now, when you run your application, the 80x87 will be ignored.  To undefine the environment variable, enter the command:

     C>SET NO87=


The LFN Environment Variable

If you have the application compiled and linked to use DOS Long file name support (LFN) then you can define the LFN environment variable to suppress usage of DOS LFN on run-time.

Using the "SET" command, define the environment variable as follows:

     C>SET LFN=N

Now, when you run your application, DOS LFN support will be ignored.  To undefine the environment variable, enter the command:

     C>SET LFN=


The Open Watcom C/C++ Run-time Initialization Routines

Source files are included in the package for the Open Watcom C/C++ application startup (or initialization) sequence.

(16-bit only) The initialization code directories/files are listed below:

Under \WATCOM\SRC\STARTUP

     WILDARGV.C    (wild card processing for argv)

     8087CW.C      (value loaded into 80x87 control word)

Under \WATCOM\SRC\STARTUP\DOS (DOS initialization)

     CSTRT086.ASM  (startup for 16-bit apps)

     DOS16M.ASM    (startup code for Tenberry Software's DOS/16M)

     CMAIN086.C    (final part of initialization sequence)

     MDEF.INC      (macros included by assembly code)

 Under \WATCOM\SRC\STARTUP\WIN (Windows initialization)

     CSTRTW16.ASM  (startup for 16-bit Windows apps)

     LIBENTRY.ASM  (startup for 16-bit Windows DLLs)

     MDEF.INC      (macros included by assembly code)

Under \WATCOM\SRC\STARTUP\OS2 (OS/2 initialization)

     CMAIN086.C    (final part of initialization sequence)

     MAINO16.C     (middle part of initialization sequence)

     CSTRTO16.ASM  (startup for 16-bit OS/2)

     EXITWMSG.H    (header file required by MAINO16.C)

     WOS2.H        (header file required by MAINO16.C)

     INITFINI.H    (header file required by MAINO16.C)

     MDEF.INC      (macros included by assembly code)

The following is a summary description of the startup files for DOS.  The startup files for Windows and OS/2 are similar.  The assembler file CSTRT086.ASM contains the first part of the initialization code and the remainder is continued in the file CMAIN086.C.  It is CMAIN086.C that calls your main routine (main).

The DOS16M.ASM file is a special version of the CSTRT086.ASM file which is required when using the Tenberry Software, Inc.  DOS/16M 286 DOS extender.

(32-bit only) The initialization code directories/files are listed below:

Under \WATCOM\SRC\STARTUP

     WILDARGV.C   (wild card processing for argv)

     8087CW.C     (value loaded into 80x87 control word)

Under \WATCOM\SRC\STARTUP\386

     CSTRT386.ASM (startup for most DOS Extenders)

     CSTRTW32.ASM (startup for 32-bit Windows)

     CSTRTX32.ASM (startup for FlashTek DOS Extender)

     CMAIN386.C   (final part of initialization sequence)

The assembler files CSTRT*.ASM contain the first part of the initialization code and the remainder is continued in the file CMAIN386.C.  It is CMAIN386.C that calls your main routine (main).

The source code is provided for those who wish to customize the initialization sequence for special applications.

The file wildargv.c contains an alternate form of "argv" processing in which wild card command line arguments are transformed into lists of matching file names.  Wild card arguments are any arguments containing "*" or "?" characters unless the argument is placed within quotes (").  Consider the following example in which we run an application called "TOUCH" with the argument "*.c".

     C>touch *.c

Suppose that the application was linked with the object code for the file wildargv.c.  Suppose that the files ap1.c, ap2.c and ap3.c are stored in the current directory.  The single argument "*.c" is transformed into a list of arguments such that:

     argc == 4

     argv[1] points to "ap1.c"

     argv[2] points to "ap2.c"

     argv[3] points to "ap3.c"

The source file wildargv.c must be compiled to produce the object file wildargv.obj.  This file must be specified before the Open Watcom C/C++ libraries in the linker command file in order to replace the standard "argv" processing.


16-bit Memory Models

This chapter describes the various 16-bit memory models supported by Open Watcom C/C++.  Each memory model is distinguished by two properties; the code model used to implement function calls and the data model used to reference data.


16-bit Code Models

There are two code models;

1.	the small code model and

2.	the big code model.

A small code model is one in which all calls to functions are made with near calls.  In a near call, the destination address is 16 bits and is relative to the segment value in segment register CS.  Hence, in a small code model, all code comprising your program, including library functions, must be less than 64K.

A big code model is one in which all calls to functions are made with far calls.  In a far call, the destination address is 32 bits (a segment value and an offset relative to the segment value).  This model allows the size of the code comprising your program to exceed 64K.

  Note:  If your program contains less than 64K of code, you should use a memory model that employs the small code model.  This will result in smaller and faster code since near calls are smaller instructions and are processed faster by the CPU.


16-bit Data Models

There are three data models;

1.	the small data model,

2.	the big data model and

3.	the huge data model.

A small data model is one in which all references to data are made with near pointers.  Near pointers are 16 bits; all data references are made relative to the segment value in segment register DS.  Hence, in a small data model, all data comprising your program must be less than 64K.

A big data model is one in which all references to data are made with far pointers.  Far pointers are 32 bits (a segment value and an offset relative to the segment value).  This removes the 64K limitation on data size imposed by the small data model.  However, when a far pointer is incremented, only the offset is adjusted.  Open Watcom C/C++ assumes that the offset portion of a far pointer will not be incremented beyond 64K.  The compiler will assign an object to a new segment if the grouping of data in a segment will cause the object to cross a segment boundary.  Implicit in this is the requirement that no individual object exceed 64K bytes.  For example, an array containing 40,000 integers does not fit into the big data model.  An object such as this should be described as huge.

A huge data model is one in which all references to data are made with far pointers.  This is similar to the big data model.  However, in the huge data model, incrementing a far pointer will adjust the offset and the segment if necessary.  The limit on the size of an object pointed to by a far pointer imposed by the big data model is removed in the huge data model.

Notes:

1.	If your program contains less than 64K of data, you should use the small data model.  This will result in smaller and faster code since references using near pointers produce fewer instructions.

2.	The huge data model should be used only if needed.  The code generated in the huge data model is not very efficient since a run-time routine is called in order to increment far pointers.  This increases the size of the code significantly and increases execution time.


Summary of 16-bit Memory Models

As previously mentioned, a memory model is a combination of a code model and a data model.  The following table describes the memory models supported by Open Watcom C/C++.

     Memory      Code        Data        Default     Default

     Model       Model       Model       Code        Data

                                         Pointer     Pointer

     --------    --------    --------    --------    --------

     tiny        small       small       near        near

     small       small       small       near        near

     medium      big         small       far         near

     compact     small       big         near        far

     large       big         big         far         far

     huge        big         huge        far         huge


Tiny Memory Model

In the tiny memory model, the application's code and data must total less than 64K bytes in size.  All code and data are placed in the same segment.  Use of the tiny memory model allows the creation of a COM file for the executable program instead of an EXE file.  For more information, see the section entitled "Creating a Tiny Memory Model Application" in this chapter.


Mixed 16-bit Memory Model

A mixed memory model application combines elements from the various code and data models.  A mixed memory model application might be characterized as one that uses the near , far , or huge keywords when describing some of its functions or data objects.

For example, a medium memory model application that uses some far pointers to data can be described as a mixed memory model.  In an application such as this, most of the data is in a 64K segment (DGROUP) and hence can be referenced with near pointers relative to the segment value in segment register DS.  This results in more efficient code being generated and better execution times than one can expect from a big data model.  Data objects outside of the DGROUP segment are described with the far keyword.


Linking Applications for the Various 16-bit Memory Models

Each memory model requires different run-time and floating-point libraries.  Each library assumes a particular memory model and should be linked only with modules that have been compiled with the same memory model.  The following table lists the libraries that are to be used to link an application that has been compiled for a particular memory model.

     Memory  Run-time      Floating-Point  Floating-Point

     Model   Library       Calls Library   Library (80x87)

     ------- --------      --------------  ---------------

     tiny    CLIBS.LIB     MATHS.LIB       MATH87S.LIB

             +CSTART_T.OBJ                 +(NO)EMU87.LIB*

     small   CLIBS.LIB     MATHS.LIB       MATH87S.LIB

                                           +(NO)EMU87.LIB*

     medium  CLIBM.LIB     MATHM.LIB       MATH87M.LIB

                                           +(NO)EMU87.LIB*

     compact CLIBC.LIB     MATHC.LIB       MATH87C.LIB

                                           +(NO)EMU87.LIB*

     large   CLIBL.LIB     MATHL.LIB       MATH87L.LIB

                                           +(NO)EMU87.LIB*

     huge    CLIBH.LIB     MATHH.LIB       MATH87H.LIB

                                           +(NO)EMU87.LIB*

* One of emu87.lib or noemu87.lib will be used with the 80x87 math libraries depending on the use of the "fpi" (include emulation) or "fpi87" (do not include emulation) options.


Creating a Tiny Memory Model Application

Tiny memory model programs are created by compiling all modules with the small memory model option and linking in the special initialization file "CSTART_T.OBJ".  This file is found in the Open Watcom C/C++ LIB286\DOS directory.  It must be the first object file specified when linking the program.

The following sequence will create the executable file "MYPROG.COM" from the file "MYPROG.C":

Example:

     C>wcc myprog /ms

     C>wlink system com file myprog

Most of the details of linking a "COM" program are handled by the "SYSTEM COM" directive (see the wlsystem.lnk file for details).  When linking a "COM" program, the message "Stack segment not found" is issued.  This message may be ignored.


16-bit Memory Layout

The following describes the segment ordering of an application linked by the Open Watcom Linker.  Note that this assumes that the "DOSSEG" linker option has been specified.

1.	all segments not belonging to group "DGROUP" with class "CODE"

2.	all other segments not belonging to group "DGROUP"

3.	all segments belonging to group "DGROUP" with class "BEGDATA"

4.	all segments belonging to group "DGROUP" not with class "BEGDATA", "BSS" or "STACK"

5.	all segments belonging to group "DGROUP" with class "BSS"

6.	all segments belonging to group "DGROUP" with class "STACK"

A special segment belonging to class "BEGDATA" is defined when linking with Open Watcom run-time libraries.  This segment is initialized with the hexadecimal byte pattern "01" and is the first segment in group "DGROUP" so that storing data at location 0 can be detected.

Segments belonging to class "BSS" contain uninitialized data.  Note that this only includes uninitialized data in segments belonging to group "DGROUP".  Segments belonging to class "STACK" are used to define the size of the stack used for your application.  Segments belonging to the classes "BSS" and "STACK" are last in the segment ordering so that uninitialized data need not take space in the executable file.

In addition to these special segments, the following conventions are used by Open Watcom C/C++.

1.	The "CODE" class contains the executable code for your application.  In a small code model, this consists of the segment "_TEXT".  In a big code model, this consists of the segments "<module>_TEXT" where <module> is the file name of the source file.

2.	The "FAR_DATA" class consists of the following:

(a)

data objects whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(b)

data objects defined using the "FAR" or "HUGE" keyword,

(c)

literals whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(d)

literals defined using the "FAR" or "HUGE" keyword.

You can override the default naming convention used by Open Watcom C/C++ to name segments.

1.	The Open Watcom C/C++ "nm" option can be used to change the name of the module.  This, in turn, changes the name of the code segment when compiling for a big code model.

2.	The Open Watcom C/C++ "nt" option can be used to specify the name of the code segment regardless of the code model used.


16-bit Assembly Language Considerations

This chapter will deal with the following topics.

1.	The data representation of the basic types supported by Open Watcom C/C++.

2.	The memory layout of a Open Watcom C/C++ program.

3.	The method for passing arguments and returning values.

4.	The two methods for passing floating-point arguments and returning floating-point values.

One method is used when one of the Open Watcom C/C++ "fpi" or "fpi87" options is specified for the generation of in-line 80x87 instructions.  When the "fpi" option is specified, an 80x87 emulator is included from a math library if the application includes floating-point operations.  When the "fpi87" option is used exclusively, the 80x87 emulator will not be included.

The other method is used when the Open Watcom C/C++ "fpc" option is specified.  In this case, the compiler generates calls to floating-point support routines in the alternate math libraries.

An understanding of the Intel 80x86 architecture is assumed.


16-bit:  Data Representation

This section describes the internal or machine representation of the basic types supported by Open Watcom C/C++.


16-bit:  Type "char"

An item of type "char" occupies 1 byte of storage.  Its value is in the following range.

     0 <= n <= 255

Note that "char" is, by default, unsigned.  The Open Watcom C/C++ compiler option "j" can be used to change the default from unsigned to signed.  If "char" is signed, an item of type "char" is in the following range.

     -128 <= n <= 127

You can force an item of type "char" to be unsigned or signed regardless of the default by defining them to be of type "unsigned char" or "signed char" respectively.


16-bit:  Type "short int"

An item of type "short int" occupies 2 bytes of storage.  Its value is in the following range.

     -32768 <= n <= 32767

Note that "short int" is signed and hence "short int" and "signed short int" are equivalent.  If an item of type "short int" is to be unsigned, it must be defined as "unsigned short int".  In this case, its value is in the following range.

     0 <= n <= 65535


16-bit:  Type "long int"

An item of type "long int" occupies 4 bytes of storage.  Its value is in the following range.

     -2147483648 <= n <= 2147483647

Note that "long int" is signed and hence "long int" and "signed long int" are equivalent.  If an item of type "long int" is to be unsigned, it must be defined as "unsigned long int".  In this case, its value is in the following range.

     0 <= n <= 4294967295


16-bit:  Type "int"

An item of type "int" occupies 2 bytes of storage.  Its value is in the following range.

     -32768 <= n <= 32767

Note that "int" is signed and hence "int" and "signed int" are equivalent.  If an item of type "int" is to be unsigned, it must be defined as "unsigned int".  In this case its value is in the following range.

     0 <= n <= 65535

If you are generating code that executes in 16-bit mode, "short int" and "int" are equivalent, "unsigned short int" and "unsigned int" are equivalent, and "signed short int" and "signed int" are equivalent.  This may not be the case in other environments where "int" and "long int" are 4 bytes.


16-bit:  Type "float"

A datum of type "float" is an approximate representation of a real number.  Each datum of type "float" occupies 4 bytes.  If m is the magnitude of x (an item of type "float") then x can be approximated if

      -126           128

     2      <= m <  2

or in more approximate terms if

     1.175494e-38 <= m <= 3.402823e38

Data of type "float" are represented internally as follows.  Note that bytes are stored in memory with the least significant byte first and the most significant byte last.

     +---+---------+---------------------+

     | S | Biased  |      Significand    |

     |   | Exponent|                     |

     +---+---------+---------------------+

      31    30-23           22-0

Notes

S

S = Sign bit (0=positive, 1=negative)

Exponent

The exponent bias is 127 (i.e., exponent value 1 represents 2**-126; exponent value 127 represents 2**0; exponent value 254 represents 2**127; etc.).  The exponent field is 8 bits long.

Significand

The leading bit of the significand is always 1, hence it is not stored in the significand field.  Thus the significand is always "normalized".  The significand field is 23 bits long.

Zero

A real zero quantity occurs when the sign bit, exponent, and significand are all zero.

Infinity

When the exponent field is all 1 bits and the significand field is all zero bits then the quantity represents positive or negative infinity, depending on the sign bit.

Not Numbers

When the exponent field is all 1 bits and the significand field is non-zero then the quantity is a special value called a NAN (Not-A-Number).

When the exponent field is all 0 bits and the significand field is non-zero then the quantity is a special value called a "denormal" or nonnormal number.


16-bit:  Type "double"

A datum of type "double" is an approximate representation of a real number.  The precision of a datum of type "double" is greater than or equal to one of type "float".  Each datum of type "double" occupies 8 bytes.  If m is the magnitude of x (an item of type "double") then x can be approximated if

      -1022          1024

     2      <= m <  2

or in more approximate terms if

     2.2250738585072e-308 <= m <= 1.79769313486232e308

Data of type "double" are represented internally as follows.  Note that bytes are stored in memory with the least significant byte first and the most significant byte last.

     +---+---------+--------------------------------------+

     | S | Biased  |              Significand             |

     |   | Exponent|                                      |

     +---+---------+--------------------------------------+

      63    62-52                   51-0

Notes:

S

S = Sign bit (0=positive, 1=negative)

Exponent

The exponent bias is 1023 (i.e., exponent value 1 represents 2**-1022; exponent value 1023 represents 2**0; exponent value 2046 represents 2**1023; etc.).  The exponent field is 11 bits long.

Significand

The leading bit of the significand is always 1, hence it is not stored in the significand field.  Thus the significand is always "normalized".  The significand field is 52 bits long.

Zero

A double precision zero quantity occurs when the sign bit, exponent, and significand are all zero.

Infinity

When the exponent field is all 1 bits and the significand field is all zero bits then the quantity represents positive or negative infinity, depending on the sign bit.

Not Numbers

When the exponent field is all 1 bits and the significand field is non-zero then the quantity is a special value called a NAN (Not-A-Number).

When the exponent field is all 0 bits and the significand field is non-zero then the quantity is a special value called a "denormal" or nonnormal number.


16-bit:  Memory Layout

The following describes the segment ordering of an application linked by the Open Watcom Linker.  Note that this assumes that the "DOSSEG" linker option has been specified.

1.	all segments not belonging to group "DGROUP" with class "CODE"

2.	all other segments not belonging to group "DGROUP"

3.	all segments belonging to group "DGROUP" with class "BEGDATA"

4.	all segments belonging to group "DGROUP" not with class "BEGDATA", "BSS" or "STACK"

5.	all segments belonging to group "DGROUP" with class "BSS"

6.	all segments belonging to group "DGROUP" with class "STACK"

A special segment belonging to class "BEGDATA" is defined when linking with Open Watcom run-time libraries.  This segment is initialized with the hexadecimal byte pattern "01" and is the first segment in group "DGROUP" so that storing data at location 0 can be detected.

Segments belonging to class "BSS" contain uninitialized data.  Note that this only includes uninitialized data in segments belonging to group "DGROUP".  Segments belonging to class "STACK" are used to define the size of the stack used for your application.  Segments belonging to the classes "BSS" and "STACK" are last in the segment ordering so that uninitialized data need not take space in the executable file.

In addition to these special segments, the following conventions are used by Open Watcom C/C++.

1.	The "CODE" class contains the executable code for your application.  In a small code model, this consists of the segment "_TEXT".  In a big code model, this consists of the segments "<module>_TEXT" where <module> is the file name of the source file.

2.	The "FAR_DATA" class consists of the following:

(a)

data objects whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(b)

data objects defined using the "FAR" or "HUGE" keyword,

(c)

literals whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(d)

literals defined using the "FAR" or "HUGE" keyword.

You can override the default naming convention used by Open Watcom C/C++ to name segments.

1.	The Open Watcom C/C++ "nm" option can be used to change the name of the module.  This, in turn, changes the name of the code segment when compiling for a big code model.

2.	The Open Watcom C/C++ "nt" option can be used to specify the name of the code segment regardless of the code model used.


16-bit:  Calling Conventions for Non-80x87 Applications

The following sections describe the calling convention used when compiling with the "fpc" compiler option.


16-bit:  Passing Arguments Using Register-Based Calling Conventions

How arguments are passed to a function with register-based calling conventions is determined by the size (in bytes) of the argument and where in the argument list the argument appears.  Depending on the size, arguments are either passed in registers or on the stack.  Arguments such as structures are almost always passed on the stack since they are generally too large to fit in registers.  Since arguments are processed from left to right, the first few arguments are likely to be passed in registers (if they can fit) and, if the argument list contains many arguments, the last few arguments are likely to be passed on the stack.

The registers used to pass arguments to a function are AX, BX, CX and DX.  The following algorithm describes how arguments are passed to functions.

Initially, we have the following registers available for passing arguments:  AX, DX, BX and CX.  Note that registers are selected from this list in the order they appear.  That is, the first register selected is AX and the last is CX.  For each argument Ai, starting with the left most argument, perform the following steps.

1.	If the size of Ai is 1 byte, convert it to 2 bytes and proceed to the next step.  If Ai is of type "unsigned char", it is converted to an "unsigned int".  If Ai is of type "signed char", it is converted to a "signed int".  If Ai is a 1-byte structure, the padding is determined by the compiler.

2.	If an argument has already been assigned a position on the stack, Ai will also be assigned a position on the stack.  Otherwise, proceed to the next step.

3.	If the size of Ai is 2 bytes, select a register from the list of available registers.  If a register is available, Ai is assigned that register.  The register is then removed from the list of available registers.  If no registers are available, Ai will be assigned a position on the stack.

4.	If the size of Ai is 4 bytes, select a register pair from the following list of combinations:  [DX AX] or [CX BX].  The first available register pair is assigned to Ai and removed from the list of available pairs.  The high-order 16 bits of the argument are assigned to the first register in the pair; the low-order 16 bits are assigned to the second register in the pair.  If none of the above register pairs is available, Ai will be assigned a position on the stack.

5.	If the type of Ai is "double" or "float" (in the absence of a function prototype), select [AX BX CX DX] from the list of available registers.  All four registers are removed from the list of available registers.  The high-order 16 bits of the argument are assigned to the first register and the low-order 16 bits are assigned to the fourth register.  If any of the four registers is not available, Ai will be assigned a position on the stack.

6.	All other arguments will be assigned a position on the stack.

Notes:

1.	Arguments that are assigned a position on the stack are padded to a multiple of 2 bytes.  That is, if a 3-byte structure is assigned a position on the stack, 4 bytes will be pushed on the stack.

2.	Arguments that are assigned a position on the stack are pushed onto the stack starting with the rightmost argument.


16-bit:  Sizes of Predefined Types

The following table lists the predefined types, their size as returned by the "sizeof" function, the size of an argument of that type and the registers used to pass that argument if it was the only argument in the argument list.

    Basic

Type    "sizeof"    Argument  Registers

                    Size      Used

    char      1       2       [AX]

    short int 2       2       [AX]

    int       2       2       [AX]

    long int  4       4       [DX AX]

    float     4       8       [AX BX CX DX]

    double    8       8       [AX BX CX DX]

    near

pointer      2       2        [AX]

    far

pointer       4       4       [DX AX]

    huge

pointer      4       4        [DX AX]

Note that the size of the argument listed in the table assumes that no function prototypes are specified.  Function prototypes affect the way arguments are passed.  This will be discussed in the section entitled "Effect of Function Prototypes on Arguments".

Notes:

1.	Provided no function prototypes exist, an argument will be converted to a default type as described in the following table.

Argument Type

Passed As

char

unsigned int

signed char

signed int

unsigned char

unsigned int

float

double


16-bit:  Size of Enumerated Types

The integral type of an enumerated type is determined by the values of the enumeration constants.  In strict ISO/ANSI C mode, all enumerated constants are of type int.  In the extensions mode, the compiler will use the smallest integral type possible (excluding long ints) that can represent all values of the enumerated type.  For instance, if the minimum and maximum values of the enumeration constants are in the range -128 and 127, the enumerated type will be equivalent to a signed char (size = 1 byte).  All references to enumerated constants in the previous instance will have type signed char.  An enumerated constant is always promoted to an int when passed as an argument.


16-bit:  Effect of Function Prototypes on Arguments

Function prototypes define the types of the formal parameters of a function.  Their appearance affects the way in which arguments are passed.  An argument will be converted to the type of the corresponding formal parameter in the function prototype.  Consider the following example.

     void prototype( float x, int i );

     void main()

     {

       float x;

       int   i;

       x = 3.14;

       i = 314;

       prototype( x, i );

       rtn( x, i );

     }

The function prototype for prototype specifies that the first argument is to be passed as a "float" and the second argument is to be passed as an "int".  This results in the first argument being passed in registers DX and AX and the second argument being passed in register BX.

If no function prototype is given, as is the case for the function rtn, the first argument will be passed as a "double" and the second argument would be passed as an "int".  This results in the first argument being passed in registers AX, BX, CX and DX and the second argument being passed on the stack.

Note that even though both prototype and rtn were called with identical argument lists, the way in which the arguments were passed was completely different simply because a function prototype for prototype was specified.  Function prototyping is an excellent way to guarantee that arguments will be passed as expected to your assembly language function.


16-bit:  Interfacing to Assembly Language Functions

Consider the following example.

Example:

     void main()

     {

         long int x;

         int      i;

         long int y;

         x = 7;

         i = 77;

         y = 777;

         myrtn( x, i, y );

     }

myrtn is an assembly language function that requires three arguments.  The first argument is of type "long int", the second argument is of type "int" and the third argument is again of type "long int".  Using the rules for register-based calling conventions, these arguments will be passed to myrtn in the following way:

1.	The first argument will be passed in registers DX and AX leaving BX and CX as available registers for other arguments.

2.	The second argument will be passed in register BX leaving CX as an available register for other arguments.

3.	The third argument will not fit in register CX (its size is 4 bytes) and hence will be pushed on the stack.

Let us look at the stack upon entry to myrtn.

     Small Code Model

     Offset

             +----------------+

       0     | return address | <- SP points here

             +----------------+

       2     | argument #3    |

             |                |

             +----------------+

       6     |                |

     Big Code Model

     Offset

             +----------------+

       0     | return address | <- SP points here

             |                |

             +----------------+

       4     | argument #3    |

             |                |

             +----------------+

       8     |                |

Notes:

1.	The return address is the top element on the stack.  In a small code model, the return address is 1 word (16 bits); in a big code model, the return address is 2 words (32 bits).

Register SP cannot be used as a base register to address the third argument on the stack.  Register BP is normally used to address arguments on the stack.  Upon entry to the function, register BP is set to point to the stack but before doing so we must save its contents.  The following two instructions achieve this.

     push    BP           ; save current value of BP

     mov     BP,SP        ; get access to arguments

After executing these instructions, the stack looks like this.

     Small Code Model

     Offset

             +----------------+

       0     | saved BP       | <- BP and SP point here

             +----------------+

       2     | return address |

             +----------------+

       4     | argument #3    |

             |                |

             +----------------+

       8     |                |

     Big Code Model

     Offset

             +----------------+

       0     | saved BP       | <- BP and SP point here

             +----------------+

       2     | return address |

             |                |

             +----------------+

       6     | argument #3    |

             |                |

             +----------------+

      10     |                |

As the above diagrams show, the third argument is at offset 4 from register BP in a small code model and offset 6 in a big code model.

Upon exit from myrtn, we must restore the value of BP.  The following two instructions achieve this.

     mov     SP,BP        ; restore stack pointer

     pop     BP           ; restore BP

The following is a sample assembly language function which implements myrtn.

     Small Memory Model (small code, small data)

     DGROUP        group   _DATA, _BSS

     _TEXT         segment byte public 'CODE'

                   assume  CS:_TEXT

                   assume  DS:DGROUP

                   public  myrtn_

     myrtn_        proc    near

                   push    BP

                   ; save BP

                   mov     BP,SP     ; get access to arguments

     ;

     ; body of function

     ;

                   mov     SP,BP     ; restore SP

                   pop     BP

                   ; restore BP

                   ret     4         ; return and pop last arg

     myrtn_        endp

     _TEXT         ends

     Large Memory Model (big code, big data)

     DGROUP        group   _DATA, _BSS

     MYRTN_TEXT segment byte public 'CODE'

                   assume  CS:MYRTN_TEXT

                   public  myrtn_

     myrtn_        proc    far

                   push    BP

                   ; save BP

                   mov     BP,SP     ; get access to arguments

     ;

     ; body of function

     ;

                   mov     SP,BP     ; restore SP

                   pop     BP

                   ; restore BP

                   ret     4         ; return and pop last arg

     myrtn_        endp

     MYRTN_TEXT ends

Notes:

1.	Global function names must be followed with an underscore.  Global variable names must be preceded with an underscore.

2.	All used 80x86 registers must be saved on entry and restored on exit except those used to pass arguments and return values, and AX, which is considered a stratch register.  Note that segment registers only have to saved and restored if you are compiling your application with the "r" option.

3.	The direction flag must be clear before returning to the caller.

4.	In a small code model, any segment containing executable code must belong to the segment "_TEXT" and the class "CODE".  The segment "_TEXT" must have a "combine" type of "PUBLIC".  On entry, CS contains the segment address of the segment "_TEXT".  In a big code model there is no restriction on the naming of segments which contain executable code.

5.	In a small data model, segment register DS contains the segment address of the group "DGROUP".  This is not the case in a big data model.

6.	When writing assembly language functions for the small code model, you must declare them as "near".  If you wish to write assembly language functions for the big code model, you must declare them as "far".

7.	In general, when naming segments for your code or data, you should follow the conventions described in the section entitled "Memory Layout" in this chapter.

8.	If any of the arguments was pushed onto the stack, the called routine must pop those arguments off the stack in the "ret" instruction.


16-bit:  Functions with Variable Number of Arguments

A function prototype with a parameter list that ends with ",..." has a variable number of arguments.  In this case, all arguments are passed on the stack.  Since no prototyping information exists for arguments represented by ",...", those arguments are passed as described in the section "Passing Arguments".


16-bit:  Returning Values from Functions

The way in which function values are returned depends on the size of the return value.  The following examples describe how function values are to be returned.  They are coded for a small code model.

1.	1-byte values are to be returned in register AL.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret1_

     Ret1_   proc    near   ; char Ret1()

             mov     AL,'G'

             ret

     Ret1_   endp

     _TEXT   ends

             end

2.	2-byte values are to be returned in register AX.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret2_

     Ret2_   proc    near   ; short int Ret2()

             mov     AX,77

             ret

     Ret2_   endp

     _TEXT   ends

             end

3.	4-byte values are to be returned in registers DX and AX with the most significant word in register DX.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret4_

     Ret4_   proc    near   ; long int Ret4()

             mov     AX,word ptr CS:Val4+0

             mov     DX,word ptr CS:Val4+2

             ret

     Val4    dd      7777777

     Ret4_   endp

     _TEXT   ends

             end

4.	8-byte values, except structures, are to be returned in registers AX, BX, CX and DX with the most significant word in register AX.

Example:

             .8087

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret8_

     Ret8_   proc    near   ; double Ret8()

             mov     DX,word ptr CS:Val8+0

             mov     CX,word ptr CS:Val8+2

             mov     BX,word ptr CS:Val8+4

             mov     AX,word ptr CS:Val8+6

             ret

     Val8:   dq      7.7

     Ret8_   endp

     _TEXT   ends

             end

The ".8087" pseudo-op must be specified so that all floating-point constants are generated in 8087 format.  When using the "fpc" (floating-point calls) option, "float" and "double" are returned in registers.  See section "Returning Values in 80x87-based Applications" when using the "fpi" or "fpi87" options.

5.	Otherwise, the caller allocates space on the stack for the return value and sets register SI to point to this area.  In a big data model, register SI contains an offset relative to the segment value in segment register SS.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  RetX_

     ;

     ; struct int_values {

     ;     int value1, value2, value3, value4, value5;

     ;                   };

     ;

     RetX_   proc    near ; struct int_values RetX()

             mov     word ptr SS:0[SI],71

             mov     word ptr SS:4[SI],72

             mov     word ptr SS:8[SI],73

             mov     word ptr SS:12[SI],74

             mov     word ptr SS:16[SI],75

             ret

     RetX_   endp

     _TEXT   ends

             end

When returning values on the stack, remember to use a segment override to the stack segment (SS).

The following is an example of a Open Watcom C/C++ program calling the above assembly language subprograms.

     #include <stdio.h>

     struct int_values {

         int value1;

         int value2;

         int value3;

         int value4;

         int value5;

     };

     extern  char              Ret1(void);

     extern  short int         Ret2(void);

     extern  long int          Ret4(void);

     extern  double            Ret8(void);

     extern  struct int_values RetX(void);

     void main()

     {

         struct int_values x;

         printf( "Ret1 = %c\n", Ret1() );

         printf( "Ret2 = %d\n", Ret2() );

         printf( "Ret4 = %ld\n", Ret4() );

         printf( "Ret8 = %f\n", Ret8() );

         x = RetX();

         printf( "RetX1 = %d\n", x.value1 );

         printf( "RetX2 = %d\n", x.value2 );

         printf( "RetX3 = %d\n", x.value3 );

         printf( "RetX4 = %d\n", x.value4 );

         printf( "RetX5 = %d\n", x.value5 );

     }

The above function should be compiled for a small code model (use the "ms" or "mc" compiler option).


16-bit:  Calling Conventions for 80x87-based Applications

When a source file is compiled by Open Watcom C/C++ with one of the "fpi" or "fpi87" options, all floating-point arguments are passed on the 80x86 stack.  The rules for passing arguments are as follows.

1.	If the argument is not floating-point, use the procedure described earlier in this chapter.

2.	If the argument is floating-point, it is assigned a position on the 80x86 stack.


16-bit:  Passing Values in 80x87-based Applications

Consider the following example.

Example:

     extern  void    myrtn(int,float,double,long int);

     void main()

     {

         float    x;

         double   y;

         int      i;

         long int j;

         x = 7.7;

         i = 7;

         y = 77.77

         j = 77;

         myrtn( i, x, y, j );

     }

myrtn is an assembly language function that requires four arguments.  The first argument is of type "int" ( 2 bytes), the second argument is of type "float" (4 bytes), the third argument is of type "double" (8 bytes) and the fourth argument is of type "long int" (4 bytes).  These arguments will be passed to myrtn in the following way:

1.	The first argument will be passed in register AX leaving BX, CX and DX as available registers for other arguments.

2.	The second argument will be passed on the 80x86 stack since it is a floating-point argument.

3.	The third argument will also be passed on the 80x86 stack since it is a floating-point argument.

4.	The fourth argument will be passed on the 80x86 stack since a previous argument has been assigned a position on the 80x86 stack.

Remember, arguments are pushed on the stack from right to left.  That is, the rightmost argument is pushed first.

Any assembly language function must obey the following rule.

1.	All arguments passed on the stack must be removed by the called function.

The following is a sample assembly language function which implements myrtn.

Example:

             .8087

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  myrtn_

     myrtn_  proc    near

     ;

     ; body of function

     ;

             ret 16           ; return and pop arguments

     myrtn_  endp

     _TEXT   ends

             end

Notes:

1.	Function names must be followed by an underscore.

2.	All used 80x86 registers must be saved on entry and restored on exit except those used to pass arguments and return values, and EAX, which is considered a stratch register.  Note that segment registers only have to saved and restored if you are compiling your application with the "r" option.  In this example, AX does not have to be saved as it was used to pass the first argument.  Floating-point registers can be modified without saving their contents.

3.	The direction flag must be clear before returning to the caller.

4.	This function has been written for a small code model.  Any segment containing executable code must belong to the class "CODE" and the segment "_TEXT".  On entry, CS contains the segment address of the segment "_TEXT".  The above restrictions do not apply in a big code memory model.

5.	When writing assembly language functions for a small code model, you must declare them as "near".  If you wish to write assembly language functions for a big code model, you must declare them as "far".


16-bit:  Returning Values in 80x87-based Applications

Floating-point values are returned in ST(0) when using the "fpi" or "fpi87" options.  All other values are returned in the manner described earlier in this chapter.


16-bit Pragmas

A pragma is a compiler directive that provides the following capabilities.

•	Pragmas allow you to specify certain compiler options.

•	Pragmas can be used to direct the Open Watcom C/C++ code generator to emit specialized sequences of code for calling functions which use argument passing and value return techniques that differ from the default used by Open Watcom C/C++.

•	Pragmas can be used to describe attributes of functions (such as side effects) that are not possible at the C/C++ language level.  The code generator can use this information to generate more efficient code.

•	Any sequence of in-line machine language instructions, including DOS and BIOS function calls, can be generated in the object code.

Pragmas are specified in the source file using the pragma directive.  The following notation is used to describe the syntax of pragmas.

keywords

A keyword is shown in a mono-spaced courier font.

program-item

A program-item is shown in a roman bold-italics font.  A program-item is a symbol name or numeric value supplied by the programmer.

punctuation

A punctuation character shown in a mono-spaced courier font must be entered as is.

A punctuation character shown in a roman bold-italics font is used to describe syntax.  The following syntactical notation is used.

[abc]

The item abc is optional.

{abc}

The item abc may be repeated zero or more times.

a|b|c

One of a, b or c may be specified.

a ::= b

The item a is defined in terms of b.

(a)

Item a is evaluated first.

The following classes of pragmas are supported.

•	pragmas that specify options

•	pragmas that specify default libraries

•	pragmas that describe the way structures are stored in memory

•	pragmas that provide auxiliary information used for code generation


16-bit:  Using Pragmas to Specify Options

Currently, the following options can be specified with pragmas:

unreferenced

The "unreferenced" option controls the way Open Watcom C/C++ handles unused symbols.  For example,

     #pragma on (unreferenced);

will cause Open Watcom C/C++ to issue warning messages for all unused symbols.  This is the default.  Specifying

     #pragma off (unreferenced);

will cause Open Watcom C/C++ to ignore unused symbols.  Note that if the warning level is not high enough, warning messages for unused symbols will not be issued even if "unreferenced" was specified.

check_stack

The "check_stack" option controls the way stack overflows are to be handled.  For example,

     #pragma on (check_stack);

will cause stack overflows to be detected and

     #pragma off (check_stack);

will cause stack overflows to be ignored.  When "check_stack" is on, Open Watcom C/C++ will generate a run-time call to a stack-checking routine at the start of every routine compiled.  This run-time routine will issue an error if a stack overflow occurs when invoking the routine.  The default is to check for stack overflows.  Stack overflow checking is particularly useful when functions are invoked recursively.  Note that if the stack overflows and stack checking has been suppressed, unpredictable results can occur.

If a stack overflow does occur during execution and you are sure that your program is not in error (i.e.  it is not unnecessarily recursing), you must increase the stack size.  This is done by linking your application again and specifying the "STACK" option to the Open Watcom Linker with a larger stack size.

It is also possible to specify more than one option in a pragma as illustrated by the following example.

     #pragma on (check_stack unreferenced);

reuse_duplicate_strings (C only)

(C Only) The "reuse_duplicate_strings" option controls the way Open Watcom C handles identical strings in an expression.  For example,

     #pragma on (reuse_duplicate_strings);

will cause Open Watcom C to reuse identical strings in an expression.  This is the default.  Specifying

     #pragma off (reuse_duplicate_strings);

will cause Open Watcom C to generate additional copies of the identical string.  The following example shows where this may be of importance to the way the application behaves.

Example:

     #include <stdio.h>

     #pragma off (reuse_duplicate_strings)

     void poke( char *, char * );

     void main()

       {

         poke( "Hello world\n", "Hello world\n" );

       }

     void poke( char *x, char *y )

       {

         x[3] = 'X';

         printf( x );

         y[4] = 'Y';

         printf( y );

       }

     /*

     Default output:

     HelXo world

     HelXY world

     */


16-bit:  Using Pragmas to Specify Default Libraries

Default libraries are specified in special object module records.  Library names are extracted from these special records by the Open Watcom Linker.  When unresolved references remain after processing all object modules specified in linker "FILE" directives, these default libraries are searched after all libraries specified in linker "LIBRARY" directives have been searched.

By default, that is if no library pragma is specified, the Open Watcom C/C++ compiler generates, in the object file defining the main program, default libraries corresponding to the memory model and floating-point model used to compile the file.  For example, if you have compiled the source file containing the main program for the medium memory model and the floating-point calls floating-point model, the libraries "clibm" and "mathm" will be placed in the object file.

If you wish to add your own default libraries to this list, you can do so with a library pragma.  Consider the following example.

     #pragma library (mylib);

The name "mylib" will be added to the list of default libraries specified in the object file.

If the library specification contains characters such as '\', ':' or ',' (i.e., any character not allowed in a C identifier), you must enclose it in double quotes as in the following example.

     #pragma library ("\watcom\lib286\dos\graph.lib");

     #pragma library ("\watcom\lib386\dos\graph.lib");

If you wish to specify more than one library in a library pragma you must separate them with spaces as in the following example.

     #pragma library (mylib "\watcom\lib286\dos\graph.lib");

     #pragma library (mylib "\watcom\lib386\dos\graph.lib");


16-bit:  The ALIAS Pragma (C Only)

The "alias" pragma can be used to emit alias records in the object file, causing the linker to substitute references to a specified symbol with references to another symbol.  Either identifiers or names (strings) may be used.  Strings are used verbatim, while names corresponding to identifiers are derived as appropriate for the kind and calling convention of the symbol.  The following describes the form of the "alias" pragma.

     #pragma alias ( alias, subst ) [;]

where

description

alias

is either a name or an identifier of the symbol to be aliased.

subst

is either a name or an identifier of the symbol that references to alias will be replaced with.

Consider the following example.

     extern int var;

     void fn( void )

     {

         var = 3;

     }

     #pragma alias ( var, "other_var" );

Instead of var the linker will reference symbol named "other_var".  Symbol var need not be defined, although "other_var" has to be.


16-bit:  The ALLOC_TEXT Pragma (C Only)

The "alloc_text" pragma can be used to specify the name of the text segment into which the generated code for a function, or a list of functions, is to be placed.  The following describes the form of the "alloc_text" pragma.

     #pragma alloc_text ( seg_name, fn {, fn} ) [;]

where

description

seg_name

is the name of the text segment.

fn

is the name of a function.

Consider the following example.

     extern int fn1(int);

     extern int fn2(void);

     #pragma alloc_text ( my_text, fn1, fn2 );

The code for the functions fn1 and fn2 will be placed in the segment my_text.  Note:  function prototypes for the named functions must exist prior to the "alloc_text" pragma.


16-bit:  The CODE_SEG Pragma

The "code_seg" pragma can be used to specify the name of the text segment into which the generated code for functions is to be placed.  The following describes the form of the "code_seg" pragma.

     #pragma code_seg ( seg_name [, class_name] ) [;]

where

description

seg_name

is the name of the text segment optionally enclosed in quotes.  Also, seg_name may be a macro as in:

     #define seg_name "MY_CODE_SEG"

     #pragma code_seg ( seg_name );

class_name

is the optional class name of the text segment and may be enclosed in quotes.  Please note that in order to be recognized by the linker as code, a class name has to end in "CODE".  Also, class_name may be a macro as in:

     #define class_name "MY_CODE"

     #pragma code_seg ( "MY_CODE_SEG", class_name );

Consider the following example.

     #pragma code_seg ( my_text );

     int incr( int i )

     {

         return( i + 1 );

     }

     int decr( int i )

     {

         return( i - 1 );

     }

The code for the functions incr and decr will be placed in the segment my_text.

To return to the default segment, do not specify any string between the opening and closing parenthesis.

     #pragma code_seg ();


16-bit:  The COMMENT Pragma

The "comment" pragma can be used to place a comment record in an object file or executable file.  The following describes the form of the "comment" pragma.

     #pragma comment ( comment_type [, "comment_string"] ) [;]

where

description

comment_type

specifies the type of comment record.  The allowable comment types are:

lib

Default libraries are specified in special object module records.  Library names are extracted from these special records by the Open Watcom Linker.  When unresolved references remain after processing all object modules specified in linker "FILE" directives, these default libraries are searched after all libraries specified in linker "LIBRARY" directives have been searched.

The "lib" form of this pragma offers the same features as the "library" pragma.  See the section entitled 16-bit:  Using Pragmas to Specify Default Libraries for more information.

"comment_string"

is an optional string literal that provides additional information for some comment types.

Consider the following example.

     #pragma comment ( lib, "mylib" );


16-bit:  The DATA_SEG Pragma

The "data_seg" pragma can be used to specify the name of the segment into which data is to be placed.  The following describes the form of the "data_seg" pragma.

     #pragma data_seg ( seg_name [, class_name] ) [;]

where

description

seg_name

is the name of the data segment and may be enclosed in quotes.  Also, seg_name may be a macro as in:

     #define seg_name "MY_DATA_SEG"

     #pragma data_seg ( seg_name );

class_name

is the optional class name of the data segment and may be enclosed in quotes.  Also, class_name may be a macro as in:

     #define class_name "MY_CLASS"

     #pragma data_seg ( "MY_DATA_SEG", class_name );

Consider the following example.

     #pragma data_seg ( my_data );

     static int i;

     static int j;

The data for i and j will be placed in the segment my_data.

To return to the default segment, do not specify any string between the opening and closing parenthesis.

     #pragma data_seg ();


16-bit:  The DISABLE_MESSAGE Pragma

The "disable_message" pragma disables the issuance of specified diagnostic messages.  The form of the "disable_message" pragma is as follows.

     #pragma disable_message ( msg_num {, msg_num} ) [;]

where

description

msg_num

is the number of the diagnostic message.  This number corresponds to the number issued by the compiler.  Make sure to strip all leading zeroes from the message number (to avoid interpretation as an octal constant).

See also the description of 16-bit:  The ENABLE_MESSAGE Pragma.


16-bit:  The DUMP_OBJECT_MODEL Pragma (C++ Only)

The "dump_object_model" pragma causes the C++ compiler to print information about the object model for an indicated class or an enumeration name to the diagnostics file.  For class names, this information includes the offsets and sizes of fields within the class and within base classes.  For enumeration names, this information consists of a list of all the enumeration constants with their values.

The general form of the "dump_object_model" pragma is as follows.

     #pragma dump_object_model class [;]

     #pragma dump_object_model enumeration [;]

     class ::= a defined C++ class free of errors

     enumeration ::= a defined C++ enumeration name

This pragma is designed to be used for information purposes only.


16-bit:  The ENABLE_MESSAGE Pragma

The "enable_message" pragma re-enables the issuance of specified diagnostic messages that have been previously disabled.  The form of the "enable_message" pragma is as follows.

     #pragma enable_message ( msg_num {, msg_num} ) [;]

where

description

msg_num

is the number of the diagnostic message.  This number corresponds to the number issued by the compiler.  Make sure to strip all leading zeroes from the message number (to avoid interpretation as an octal constant).

See also the description of 16-bit:  The DISABLE_MESSAGE Pragma.


16-bit:  The ENUM Pragma

The "enum" pragma affects the underlying storage-definition for subsequent enum declarations.  The forms of the "enum" pragma are as follows.

     #pragma enum int [;]

     #pragma enum minimum [;]

     #pragma enum original [;]

     #pragma enum pop [;]

where

description

int

Make int the underlying storage definition (same as the "ei" compiler option).

minimum

Minimize the underlying storage definition (same as not specifying the "ei" compiler option).

original

Reset back to the original compiler option setting (i.e., what was or was not specified on the command line).

pop

Restore the previous setting.

The first three forms all push the previous setting before establishing the new setting.


16-bit:  The ERROR Pragma

The "error" pragma can be used to issue an error message with the specified text.  The following describes the form of the "error" pragma.

     #pragma error "error text" [;]

where

description

"error text"

is the text of the message that you wish to display.

You should use the ISO #error directive rather than this pragma.  This pragma is provided for compatibility with legacy code.  The following is an example.

     #if defined(__386__)

         ...

     #elseif defined(__86__)

         ...

     #else

     #pragma error ( "neither __386__ or __86__ defined" );

     #endif


16-bit:  The EXTREF Pragma

The "extref" pragma is used to generate a reference to an external function or data item.  The form of the "extref" pragma is as follows.

     #pragma extref name [;]

where

description

name

is the name of an external function or data item.  It must be declared to be an external function or data item before the pragma is encountered.  In C++, when name is a function, it must not be overloaded.

This pragma causes an external reference for the function or data item to be emitted into the object file even if that function or data item is not referenced in the module.  The external reference will cause the linker to include the module containing that name in the linked program or DLL.

This is useful for debugging since you can cause debugging routines (callable from within debugger) to be included into a program or DLL to be debugged.

In C++, you can also force constructors and/or destructors to be called for a data item without necessarily referencing the data item anywhere in your code.


16-bit:  The FUNCTION Pragma

Certain functions, such as those listed in the description of the "oi" and "om" options, have intrinsic forms.  These functions are special functions that are recognized by the compiler and processed in a special way.  For example, the compiler may choose to generate in-line code for the function.  The intrinsic attribute for these special functions is set by specifying the "oi" or "om" option or using an "intrinsic" pragma.  The "function" pragma can be used to remove the intrinsic attribute for a specified list of functions.

The following describes the form of the "function" pragma.

     #pragma function ( fn {, fn} ) [;]

where

description

fn

is the name of a function.

Suppose the following source code was compiled using the "om" option so that when one of the special math functions is referenced, the intrinsic form will be used.  In our example, we have referenced the function sin which does have an intrinsic form.  By specifying sin in a "function" pragma, the intrinsic attribute will be removed, causing the function sin to be treated as a regular user-defined function.

     #include <math.h>

     #pragma function( sin );

     double test( double x )

     {

         return( sin( x ) );

     }


16-bit:  The INCLUDE_ALIAS Pragma

In certain situations, it can be advantageous to remap the names of include files.  Most commonly this occurs on systems that do not support long file names when building source code that references header files with long names.

The form of the "include_alias" pragma follows.

     #pragma include_alias ( "alias_name", "real_name" ) [;]

     #pragma include_alias ( <alias_name>, <real_name> ) [;]

where

description

alias_name

is the name referenced in include directives in source code.

real_name

is the translated name that the compiler will reference instead.

The following is an example.

     #pragma include_alias( "LongFileName.h", "lfn.h" )

     #include "LongFileName.h"

In the example, the compiler will attempt to read lfn.h when LongFileName.h was included.

Note that only simple textual substitution is performed.  The aliased name must match exactly, including double quotes or angle brackets, as well as any directory separators.  Also, double quotes and angle brackets may not be mixed a single pragma.

The value of the predefined __FILE__ symbol, as well as the filename reported in error messages, will be the true filename after substitution was performed.


16-bit:  Setting Priority of Static Data Initialization (C++ Only)

The "initialize" pragma sets the priority for initialization of static data in the file.  This priority only applies to initialization of static data that requires the execution of code.  For example, the initialization of a class that contains a constructor requires the execution of the constructor.  Note that if the sequence in which initialization of static data in your program takes place has no dependencies, the "initialize" pragma need not be used.

The general form of the "initialize" pragma is as follows.

     #pragma initialize [before | after] priority [;]

     priority ::= n | library | program

where

description

n

is a number representing the priority and must be in the range 0-255.  The larger the priority, the later the point at which initialization will occur.

Priorities in the range 0-20 are reserved for the C++ compiler.  This is to ensure that proper initialization of the C++ run-time system takes place before the execution of your program.  The "library" keyword represents a priority of 32 and can be used for class libraries that require initialization before the program is initialized.  The "program" keyword represents a priority of 64 and is the default priority for any compiled code.  Specifying "before" adjusts the priority by subtracting one.  Specifying "after" adjusts the priority by adding one.

A source file containing the following "initialize" pragma specifies that the initialization of static data in the file will take place before initialization of all other static data in the program since a priority of 63 will be assigned.

Example:

     #pragma initialize before program

If we specify "after" instead of "before", the initialization of the static data in the file will occur after initialization of all other static data in the program since a priority of 65 will be assigned.

Note that the following is equivalent to the "before" example

Example:

     #pragma initialize 63

and the following is equivalent to the "after" example.

Example:

     #pragma initialize 65

The use of the "before", "after", and "program" keywords are more descriptive in the intent of the pragmas.

It is recommended that a priority of 32 (the priority used when the "library" keyword is specified) be used when developing class libraries.  This will ensure that initialization of static data defined by the class library will take place before initialization of static data defined by the program.  The following "initialize" pragma can be used to achieve this.

Example:

     #pragma initialize library


16-bit:  The INLINE_DEPTH Pragma (C++ Only)

When an in-line function is called, the function call may be replaced by the in-line expansion for that function.  This in-line expansion may include calls to other in-line functions which can also be expanded.  The "inline_depth" pragma can be used to set the number of times this expansion of in-line functions will occur for a call.

The form of the "inline_depth" pragma is as follows.

     #pragma inline_depth [(] n [)] [;]

where

description

n

is the depth of expansion.  If n is 0, no expansion will occur.  If n is 1, only the original call is expanded.  If n is 2, the original call and the in-line functions invoked by the original function will be expanded.  The default value for n is 3.  The maximum value for n is 255.  Note that no expansion of recursive in-line functions occur unless enabled using the "inline_recursion" pragma.


16-bit:  The INLINE_RECURSION Pragma (C++ Only)

The "inline_recursion" pragma controls the recursive expansion of inline functions.  The form of the "inline_recursion" pragma is as follows.

     #pragma inline_recursion [(] on | off [)] [;]

Specifying "on" will enable expansion of recursive inline functions.  The depth of expansion is specified by the "inline_depth" pragma.  The default depth is 3.  Specifying "off" suppresses expansion of recursive inline functions.  This is the default.


16-bit:  The INTRINSIC Pragma

Certain functions, those listed in the description of the "oi" option, have intrinsic forms.  These functions are special functions that are recognized by the compiler and processed in a special way.  For example, the compiler may choose to generate in-line code for the function.  The intrinsic attribute for these special functions is set by specifying the "oi" option or using an "intrinsic" pragma.

The following describes the form of the "intrinsic" pragma.

     #pragma intrinsic ( fn {, fn} ) [;]

where

description

fn

is the name of a function.

Suppose the following source code was compiled without using the "oi" option so that no function had the intrinsic attribute.  If we wanted the intrinsic form of the sin function to be used, we could specify the function in an "intrinsic" pragma.

     #include <math.h>

     #pragma intrinsic( sin );

     double test( double x )

     {

         return( sin( x ) );

     }


16-bit:  The MESSAGE Pragma

The "message" pragma can be used to issue a message with the specified text to the standard output without terminating compilation.  The following describes the form of the "message" pragma.

     #pragma message ( "message text" ) [;]

where

description

"message text"

is the text of the message that you wish to display.

The following is an example.

     #if defined(__386__)

         ...

     #else

     #pragma message ( "assuming 16-bit compile" );

     #endif


16-bit:  The ONCE Pragma

The "once" pragma can be used to indicate that the file which contains this pragma should only be opened and processed "once".  The following describes the form of the "once" pragma.

     #pragma once [;]

Assume that the file "foo.h" contains the following text.

Example:

     #ifndef _FOO_H_INCLUDED

     #define _FOO_H_INCLUDED

     #pragma once

         .

         .

         .

     #endif

The first time that the compiler processes "foo.h" and encounters the "once" pragma, it records the file's name.  Subsequently, whenever the compiler encounters a #include statement that refers to "foo.h", it will not open the include file again.  This can help speed up processing of #include files and reduce the time required to compile an application.


16-bit:  The PACK Pragma

The "pack" pragma can be used to control the way in which structures are stored in memory.  There are 4 forms of the "pack" pragma.

The following form of the "pack" pragma can be used to change the alignment of structures and their fields in memory.

     #pragma pack ( n ) [;]

where

description

n

is 1, 2, 4, 8 or 16 and specifies the method of alignment.

The alignment of structure members is described in the following table.  If the size of the member is 1, 2, 4, 8 or 16, the alignment is given for each of the "zp" options.  If the member of the structure is an array or structure, the alignment is described by the row "x".

                         zp1     zp2     zp4     zp8     zp16

     sizeof(member)  \---------------------------------------

             1       |   0       0       0       0       0

             2       |   0       2       2       2       2

             4       |   0       2       4       4       4

             8       |   0       2       4       8       8

             16      |   0       2       4       8       16

             x       |   aligned to largest member

An alignment of 0 means no alignment, 2 means word boundary, 4 means doubleword boundary, etc.  If the largest member of structure "x" is 1 byte then "x" is not aligned.  If the largest member of structure "x" is 2 bytes then "x" is aligned according to row 2.  If the largest member of structure "x" is 4 bytes then "x" is aligned according to row 4.  If the largest member of structure "x" is 8 bytes then "x" is aligned according to row 8.  If the largest member of structure "x" is 16 bytes then "x" is aligned according to row 16.

If no value is specified in the "pack" pragma, a default value of 2 is used.  Note that the default value can be changed with the "zp" Open Watcom C/C++ compiler command line option.

The following form of the "pack" pragma can be used to save the current alignment amount on an internal stack.

     #pragma pack ( push ) [;]

The following form of the "pack" pragma can be used to save the current alignment amount on an internal stack and set the current alignment.

     #pragma pack ( push, number ) [;]

The following form of the "pack" pragma can be used to restore the previous alignment amount from an internal stack.

     #pragma pack ( pop ) [;]


16-bit:  The READ_ONLY_FILE Pragma

Explicit listing of dependencies in a makefile can often be tedious in the development and maintenance phases of a project.  The Open Watcom C/C++ compiler will insert dependency information into the object file as it processes source files so that a complete snapshot of the files necessary to build the object file are recorded.  The "read_only_file" pragma can be used to prevent the name of the source file that includes it from being included in the dependency information that is written to the object file.

This pragma is commonly used in system header files since they change infrequently (and, when they do, there should be no impact on source files that have included them).

The form of the "read_only_file" pragma follows.

     #pragma read_only_file [;]

For more information on make dependencies, see the section entitled "Automatic Dependency Detection (.AUTODEPEND)" in the Open Watcom C/C++ Tools User's Guide.


16-bit:  The TEMPLATE_DEPTH Pragma (C++ Only)

The "template_depth" pragma provides a hard limit for the amount of nested template expansions allowed so that infinite expansion can be detected.

The form of the "template_depth" pragma is as follows.

     #pragma template_depth [(] n [)] [;]

where

description

n

is the depth of expansion.  If the value of n is less than 2, if will default to 2.  If n is not specified, a warning message will be issued and the default value for n will be 100.

The following example of recursive template expansion illustrates why this pragma can be useful.

Example:

     #pragma template_depth(10);

     template <class T>

     struct S {

         S<T*> x;

     };

     S<char> v;


16-bit:  The WARNING Pragma (C++ Only)

The "warning" pragma sets the level of warning messages.  The form of the "warning" pragma is as follows.

     #pragma warning msg_num level [;]

where

description

msg_num

is the number of the warning message.  This number corresponds to the number issued by the compiler.  If msg_num is "*", the level of all warning messages is changed to the specified level.  Make sure to strip all leading zeroes from the message number (to avoid interpretation as an octal constant).

level

is a number from 0 to 9 and represents the level of the warning message.  When a value of zero is specified, the warning becomes an error.


16-bit:  Auxiliary Pragmas

The following sections describe the capabilities provided by auxiliary pragmas.


16-bit:  Specifying Symbol Attributes

Auxiliary pragmas are used to describe attributes that affect code generation.  Initially, the compiler defines a default set of attributes.  Each auxiliary pragma refers to one of the following.

1.	a symbol (such as a variable or function)

2.	a type definition that resolves to a function type

3.	the default set of attributes defined by the compiler

When an auxiliary pragma refers to a particular symbol, a copy of the current set of default attributes is made and merged with the attributes specified in the auxiliary pragma.  The resulting attributes are assigned to the specified symbol and can only be changed by another auxiliary pragma that refers to the same symbol.

An example of a type definition that resolves to a function type is the following.

     typedef void (*func_type)();

When an auxiliary pragma refers to a such a type definition, a copy of the current set of default attributes is made and merged with the attributes specified in the auxiliary pragma.  The resulting attributes are assigned to each function whose type matches the specified type definition.

When "default" is specified instead of a symbol name, the attributes specified by the auxiliary pragma change the default set of attributes.  The resulting attributes are used by all symbols that have not been specifically referenced by a previous auxiliary pragma.

Note that all auxiliary pragmas are processed before code generation begins.  Consider the following example.

     code in which symbol x is referenced

     #pragma aux y <attrs_1>;

     code in which symbol y is referenced

     code in which symbol z is referenced

     #pragma aux default <attrs_2>;

     #pragma aux x <attrs_3>;

Auxiliary attributes are assigned to x, y and z in the following way.

1.	Symbol x is assigned the initial default attributes merged with the attributes specified by <attrs_2> and <attrs_3>.

2.	Symbol y is assigned the initial default attributes merged with the attributes specified by <attrs_1>.

3.	Symbol z is assigned the initial default attributes merged with the attributes specified by <attrs_2>.


16-bit:  Alias Names

When a symbol referred to by an auxiliary pragma includes an alias name, the attributes of the alias name are also assumed by the specified symbol.

There are two methods of specifying alias information.  In the first method, the symbol assumes only the attributes of the alias name; no additional attributes can be specified.  The second method is more general since it is possible to specify an alias name as well as additional auxiliary information.  In this case, the symbol assumes the attributes of the alias name as well as the attributes specified by the additional auxiliary information.

The simple form of the auxiliary pragma used to specify an alias is as follows.

     #pragma aux ( sym, alias ) [;]

where

description

sym

is any valid C/C++ identifier.

alias

is the alias name and is any valid C/C++ identifier.

Consider the following example.

     #pragma aux push_args parm [] ;

     #pragma aux ( rtn, push_args ) ;

The routine rtn assumes the attributes of the alias name push_args which specifies that the arguments to rtn are passed on the stack.

Let us look at an example in which the symbol is a type definition.

     typedef void (func_type)(int);

     #pragma aux push_args parm [];

     #pragma aux ( func_type, push_args );

     extern func_type rtn1;

     extern func_type rtn2;

The first auxiliary pragma defines an alias name called push_args that specifies the mechanism to be used to pass arguments.  The mechanism is to pass all arguments on the stack.  The second auxiliary pragma associates the attributes specified in the first pragma with the type definition func_type.  Since rtn1 and rtn2 are of type func_type, arguments to either of those functions will be passed on the stack.

The general form of an auxiliary pragma that can be used to specify an alias is as follows.

     #pragma aux ( alias ) sym aux_attrs [;]

where

description

alias

is the alias name and is any valid C/C++ identifier.

sym

is any valid C/C++ identifier.

aux_attrs

are attributes that can be specified with the auxiliary pragma.

Consider the following example.

     #pragma aux MS_C "_*"                                  \

                      parm caller []                        \

                      value struct float struct routine [ax]\

                      modify [ax bx cx dx es];

     #pragma aux (MS_C) rtn1;

     #pragma aux (MS_C) rtn2;

     #pragma aux (MS_C) rtn3;

The routines rtn1, rtn2 and rtn3 assume the same attributes as the alias name MS_C which defines the calling convention used by the Microsoft C compiler.  Whenever calls are made to rtn1, rtn2 and rtn3, the Microsoft C calling convention will be used.

Note that if the attributes of MS_C change, only one pragma needs to be changed.  If we had not used an alias name and specified the attributes in each of the three pragmas for rtn1, rtn2 and rtn3, we would have to change all three pragmas.  This approach also reduces the amount of memory required by the compiler to process the source file.

  WARNING!  The alias name MS_C is just another symbol.  If MS_C appeared in your source code, it would assume the attributes specified in the pragma for MS_C.


16-bit:  Predefined Aliases

A number of symbols are predefined by the compiler with a set of attributes that describe a particular calling convention.  These symbols can be used as aliases.  The following is a list of these symbols.

__cdecl

 __cdecl or  cdecl defines the calling convention used by Microsoft compilers.

__fastcall

 __fastcall or  fastcall defines the calling convention used by Microsoft compilers.

__fortran

 __fortran or  fortran defines the calling convention used by Open Watcom FORTRAN compilers.

__pascal

 __pascal or  pascal defines the calling convention used by OS/2 1.x and Windows 3.x API functions.

__stdcall

 __stdcall or  stdcall defines the calling convention used by Microsoft compilers.

__watcall

 __watcall or  watcall defines the calling convention used by Open Watcom compilers.

The following describes the attributes of the above alias names.


16-bit:  Predefined "__cdecl" Alias

     #pragma aux __cdecl "_*" \

                parm caller [] \

                value struct float struct routine [ax] \

                modify [ax bx cx dx es]

Notes:

1.	All symbols are preceded by an underscore character.

2.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The calling routine will remove the arguments from the stack.

3.	Floating-point values are returned in the same way as structures.  When a structure is returned, the called routine allocates space for the return value and returns a pointer to the return value in register AX.

4.	Registers AX, BX, CX and DX, and segment register ES are not saved and restored when a call is made.


16-bit:  Predefined "__pascal" Alias

     #pragma aux __pascal "^" \

                parm reverse routine [] \

                value struct float struct caller [] \

                modify [ax bx cx dx es]

Notes:

1.	All symbols are mapped to upper case.

2.	Arguments are pushed on the stack in reverse order.  That is, the first argument is pushed first, the second argument is pushed next, and so on.  The routine being called will remove the arguments from the stack.

3.	Floating-point values are returned in the same way as structures.  When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register AX will contain address of the space allocated for the return value.

4.	Registers AX, BX, CX and DX, and segment register ES are not saved and restored when a call is made.


16-bit:  Predefined "__watcall" Alias

     #pragma aux __watcall "*_" \

                parm routine [ax bx cx dx] \

                value struct caller

Notes:

1.	Symbol names are followed by an underscore character.

2.	Arguments are processed from left to right.  The leftmost arguments are passed in registers and the rightmost arguments are passed on the stack (if the registers used for argument passing have been exhausted).  Arguments that are passed on the stack are pushed from right to left.  The calling routine will remove the arguments if any were pushed on the stack.

3.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space is put into SI register.  The called routine then places the return value there.  Upon returning from the call, register AX will contain address of the space allocated for the return value.

4.	Floating-point values are returned using 80x86 registers ("fpc" option) or using 80x87 floating-point registers ("fpi" or "fpi87" option).

5.	All registers must be preserved by the called routine.


16-bit:  Alternate Names for Symbols

The following form of the auxiliary pragma can be used to describe the mapping of a symbol from its source form to its object form.

     #pragma aux sym obj_name [;]

where

description

sym

is any valid C/C++ identifier.

obj_name

is any character string enclosed in double quotes.

When specifying obj_name, some characters have a special meaning:

where

description

*

is unmodified symbol name

^

is symbol name converted to uppercase

!

is symbol name converted to lowercase

#

is a placeholder for "@nnn", where nnn is size of all function parameters on the stack; it is ignored for functions with variable argument lists, or for symbols that are not functions

\

next character is treated as literal

Several examples of source to object form symbol name translation follow:

In the following example, the name "MyRtn" will be replaced by "MyRtn_" in the object file.

     #pragma aux MyRtn "*_";

This is the default for all function names.

In the following example, the name "MyVar" will be replaced by "_MyVar" in the object file.

     #pragma aux MyVar "_*";

This is the default for all variable names.

In the following example, the lower case version "myrtn" will be placed in the object file.

     #pragma aux MyRtn "!";

In the following example, the upper case version "MYRTN" will be placed in the object file.

     #pragma aux MyRtn "^";

In the following example, the name "MyRtn" will be replaced by "_MyRtn@nnn" in the object file.  "nnn" represents the size of all function parameters.

     #pragma aux MyRtn "_*#";

In the following example, the name "MyRtn" will be replaced by "_MyRtn#" in the object file.

     #pragma aux MyRtn "_*\#";

The default mapping for all symbols can also be changed as illustrated by the following example.

     #pragma aux default "_*_";

The above auxiliary pragma specifies that all names will be prefixed and suffixed by an underscore character ('_').


16-bit:  Describing Calling Information

The following form of the auxiliary pragma can be used to describe the way a function is to be called.

     #pragma aux sym far [;]

         or

     #pragma aux sym near [;]

         or

     #pragma aux sym = in_line [;]

     in_line ::= { const | (seg id) | (offset id) | (reloff id)

                         | (float fpinst) | "asm" }

where

description

sym

is a function name.

const

is a valid C/C++ integer constant.

id

is any valid C/C++ identifier.

fpinst

is a sequence of bytes that forms a valid 80x87 instruction.  The keyword float must precede fpinst so that special fixups are applied to the 80x87 instruction.

seg

specifies the segment of the symbol id.

offset

specifies the offset of the symbol id.

reloff

specifies the relative offset of the symbol id for near control transfers.

asm

is an assembly language instruction or directive.

In the following example, Open Watcom C/C++ will generate a far call to the function myrtn.

     #pragma aux myrtn far;

Note that this overrides the calling sequence that would normally be generated for a particular memory model.  In other words, a far call will be generated even if you are compiling for a memory model with a small code model.

In the following example, Open Watcom C/C++ will generate a near call to the function myrtn.

     #pragma aux myrtn near;

Note that this overrides the calling sequence that would normally be generated for a particular memory model.  In other words, a near call will be generated even if you are compiling for a memory model with a big code model.

In the following DOS example, Open Watcom C/C++ will generate the sequence of bytes following the "=" character in the auxiliary pragma whenever a call to mode4 is encountered.  mode4 is called an in-line function.

     void mode4(void);

     #pragma aux mode4 =                \

         0xb4 0x00       /* mov AH,0 */ \

         0xb0 0x04       /* mov AL,4 */ \

         0xcd 0x10       /* int 10H  */ \

         modify [ AH AL ];

The sequence in the above DOS example represents the following lines of assembly language instructions.

     mov   AH,0       ; select function "set mode"

     mov   AL,4       ; specify mode (mode 4)

     int   10H        ; BIOS video call

The above example demonstrates how to generate BIOS function calls in-line without writing an assembly language function and calling it from your C/C++ program.  The C prototype for the function mode4 is not necessary but is included so that we can take advantage of the argument type checking provided by Open Watcom C/C++.

The following DOS example is equivalent to the above example but mnemonics for the assembly language instructions are used instead of the binary encoding of the assembly language instructions.

     void mode4(void);

     #pragma aux mode4 =     \

         "mov AH,0",         \

         "mov AL,4",         \

         "int 10H"           \

         modify [ AH AL ];

If a sequence of in-line assembly language instructions contains 80x87 floating-point instructions, each floating-point instruction must be preceded by "float".  Note that this is only required if you have specified the "fpi" compiler option; otherwise it will be ignored.

The following example generates the 80x87 "square root" instruction.

     double mysqrt(double);

     #pragma aux mysqrt parm [8087] = \

         float 0xd9 0xfa /* fsqrt */;

A sequence of in-line assembly language instructions may contain symbolic references.  In the following example, a near call to the function myalias is made whenever myrtn is called.

     extern void myalias(void);

     void myrtn(void);

     #pragma aux myrtn =                     \

         0xe8 reloff myalias /* near call */;

In the following example, a far call to the function myalias is made whenever myrtn is called.

     extern void myalias(void);

     void myrtn(void);

     #pragma aux myrtn =                                \

         0x9a offset myalias seg myalias /* far call */;


16-bit:  Loading Data Segment Register

An application may have been compiled so that the segment register DS does not contain the segment address of the default data segment (group "DGROUP").  This is usually the case if you are using a large data memory model.  Suppose you wish to call a function that assumes that the segment register DS contains the segment address of the default data segment.  It would be very cumbersome if you were forced to compile your application so that the segment register DS contained the default data segment (a small data memory model).

The following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment address of the default data segment before calling the specified function.

     #pragma aux sym parm loadds [;]

where

description

sym

is a function name.

Alternatively, the following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment address of the default data segment as part of the prologue sequence for the specified function.

     #pragma aux sym loadds [;]

where

description

sym

is a function name.


16-bit:  Defining Exported Symbols in Dynamic Link Libraries

An exported symbol in a dynamic link library is a symbol that can be referenced by an application that is linked with that dynamic link library.  Normally, symbols in dynamic link libraries are exported using the Open Watcom Linker "EXPORT" directive.  An alternative method is to use the following form of the auxiliary pragma.

     #pragma aux sym export [;]

where

description

sym

is a function name.


16-bit:  Defining Windows Callback Functions

When compiling a Microsoft Windows application, you must use the "zW" option so that special prologue/epilogue sequences are generated.  Furthermore, callback functions require larger prologue/epilogue sequences than those generated when the "zW" compiler option is specified.  The following form of the auxiliary pragma will cause a callback prologue/epilogue sequence to be generated for a callback function when compiled using the "zW" option.

     #pragma aux sym export [;]

where

description

sym

is a callback function name.

Alternatively, the "zw" compiler option can be used to generate callback prologue/epilogue sequences.  However, all functions contained in a module compiled using the "zw" option will have a callback prologue/epilogue sequence even if the functions are not callback functions.


16-bit:  Forcing a Stack Frame

Normally, a function contains a stack frame if arguments are passed on the stack or an automatic variable is allocated on the stack.  No stack frame will be generated if the above conditions are not satisfied.  The following form of the auxiliary pragma will force a stack frame to be generated under any circumstance.

     #pragma aux sym frame [;]

where

description

sym

is a function name.


16-bit:  Describing Argument Information

Using auxiliary pragmas, you can describe the calling convention that Open Watcom C/C++ is to use for calling functions.  This is particularly useful when interfacing to functions that have been compiled by other compilers or functions written in other programming languages.

The general form of an auxiliary pragma that describes argument passing is the following.

     #pragma aux sym parm { pop_info | reverse | {reg_set} } [;]

     pop_info ::= caller | routine

where

description

sym

is a function name.

reg_set

is called a register set.  The register sets specify the registers that are to be used for argument passing.  A register set is a list of registers separated by spaces and enclosed in square brackets.


16-bit:  Passing Arguments in Registers

The following form of the auxiliary pragma can be used to specify the registers that are to be used to pass arguments to a particular function.

     #pragma aux sym parm {reg_set} [;]

where

description

sym

is a function name.

reg_set

is called a register set.  The register sets specify the registers that are to be used for argument passing.  A register set is a list of registers separated by spaces and enclosed in square brackets.

Register sets establish a priority for register allocation during argument list processing.  Register sets are processed from left to right.  However, within a register set, registers are chosen in any order.  Once all register sets have been processed, any remaining arguments are pushed on the stack.

Note that regardless of the register sets specified, only certain combinations of registers will be selected for arguments of a particular type.

Note that arguments of type float and double are always pushed on the stack when the "fpi" or "fpi87" option is used.

double

Arguments of type double can only be passed in the following register combination:  AX:BX:CX:DX.  For example, if the following register set was specified for a routine having an argument of type double,

     [AX BX SI DI]

the argument would be pushed on the stack since a valid register combination for 8-byte arguments is not contained in the register set.  Note that this method for passing arguments of type double is supported only when the "fpc" option is used.  Note that this argument passing method does not include the passing of 8-byte structures.

far pointer

A far pointer can only be passed in one of the following register pairs:  DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX, BX:AX, DS:CX, DS:DX, DS:DI, DS:SI, DS:BX, DS:AX, ES:CX, ES:DX, ES:DI, ES:SI, ES:BX or ES:AX.  For example, if a far pointer is passed to a function with the following register set,

     [ES BP]

the argument would be pushed on the stack since a valid register combination for a far pointer is not contained in the register set.

long int, float

The only registers that will be assigned to 4-byte arguments (e.g., arguments of type long int,) are:  DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX and BX:AX.  For example, if the following register set was specified for a routine with one argument of type long int,

     [ES DI]

the argument would be pushed on the stack since a valid register combination for 4-byte arguments is not contained in the register set.  Note that this argument passing method includes 4-byte structures.  Note that this argument passing method includes arguments of type float but only when the "fpc" option is used.

int

The only registers that will be assigned to 2-byte arguments (e.g., arguments of type int) are:  AX, BX, CX, DX, SI and DI.  For example, if the following register set was specified for a routine with one argument of type int,

     [BP]

the argument would be pushed on the stack since a valid register combination for 2-byte arguments is not contained in the register set.

char

Arguments whose size is 1 byte (e.g., arguments of type char) are promoted to 2 bytes and are then assigned registers as if they were 2-byte arguments.

others

Arguments that do not fall into one of the above categories cannot be passed in registers and are pushed on the stack.  Once an argument has been assigned a position on the stack, all remaining arguments will be assigned a position on the stack even if all register sets have not yet been exhausted.

Notes:

1.	The default register set is [AX BX CX DX].

2.	Specifying registers AH and AL is equivalent to specifying register AX.  Specifying registers DH and DL is equivalent to specifying register DX.  Specifying registers CH and CL is equivalent to specifying register CX.  Specifying registers BH and BL is equivalent to specifying register BX.

3.	If you are compiling for a memory model with a small data model, or the "zdp" compiler option is specified, any register combination containing register DS becomes illegal.  In a small data model, segment register DS must remain unchanged as it points to the program's data segment.  Note that the "zdf" compiler option can be used to specify that register DS does not contain that segment address of the program's data segment.  In this case, register combinations containing register DS are legal.

Consider the following example.

     #pragma aux myrtn parm [ax bx cx dx] [bp si];

Suppose myrtn is a routine with 3 arguments each of type long int.

1.	The first argument will be passed in the register pair DX:AX.

2.	The second argument will be passed in the register pair CX:BX.

3.	The third argument will be pushed on the stack since BP:SI is not a valid register pair for arguments of type long int.

It is possible for registers from the second register set to be used before registers from the first register set are used.  Consider the following example.

     #pragma aux myrtn parm [ax bx cx dx] [si di];

Suppose myrtn is a routine with 3 arguments, the first of type int and the second and third of type long int.

1.	The first argument will be passed in the register AX.

2.	The second argument will be passed in the register pair CX:BX.

3.	The third argument will be passed in the register set DI:SI.

Note that registers are no longer selected from a register set after registers are selected from subsequent register sets, even if all registers from the original register set have not been exhausted.

An empty register set is permitted.  All subsequent register sets appearing after an empty register set are ignored; all remaining arguments are pushed on the stack.

Notes:

1.	If a single empty register set is specified, all arguments are passed on the stack.

2.	If no register set is specified, the default register set [AX BX CX DX] is used.


16-bit:  Forcing Arguments into Specific Registers

It is possible to force arguments into specific registers.  Suppose you have a function, say "mycopy", that copies data.  The first argument is the source, the second argument is the destination, and the third argument is the length to copy.  If we want the first argument to be passed in the register SI, the second argument to be passed in register DI and the third argument to be passed in register CX, the following auxiliary pragma can be used.

     void mycopy( char near *, char *, int );

     #pragma aux mycopy parm [SI] [DI] [CX];

Note that you must be aware of the size of the arguments to ensure that the arguments get passed in the appropriate registers.


16-bit:  Passing Arguments to In-Line Functions

For functions whose code is generated by Open Watcom C/C++ and whose argument list is described by an auxiliary pragma, Open Watcom C/C++ has some freedom in choosing how arguments are assigned to registers.  Since the code for in-line functions is specified by the programmer, the description of the argument list must be very explicit.  To achieve this, Open Watcom C/C++ assumes that each register set corresponds to an argument.  Consider the following DOS example of an in-line function called scrollactivepgup.

     void scrollactivepgup(char,char,char,char,char,char);

     #pragma aux scrollactivepgup = \

         "mov AH,6"   \

         "int 10h"    \

         parm [ch] [cl] [dh] [dl] [al] [bh] \

         modify [ah];

The BIOS video call to scroll the active page up requires the following arguments.

1.	The row and column of the upper left corner of the scroll window is passed in registers CH and CL respectively.

2.	The row and column of the lower right corner of the scroll window is passed in registers DH and DL respectively.

3.	The number of lines blanked at the bottom of the window is passed in register AL.

4.	The attribute to be used on the blank lines is passed in register BH.

When passing arguments, Open Watcom C/C++ will convert the argument so that it fits in the register(s) specified in the register set for that argument.  For example, in the above example, if the first argument to scrollactivepgup was called with an argument whose type was int, it would first be converted to char before assigning it to register CH.  Similarly, if an in-line function required its argument in register pair DX:AX and the argument was of type short int, the argument would be converted to long int before assigning it to register pair DX:AX.

In general, Open Watcom C/C++ assigns the following types to register sets.

1.	A register set consisting of a single 8-bit register (1 byte) is assigned a type of unsigned char.

2.	A register set consisting of a single 16-bit register (2 bytes) is assigned a type of unsigned short int.

3.	A register set consisting of two 16-bit registers (4 bytes) is assigned a type of unsigned long int.

4.	A register set consisting of four 16-bit registers (8 bytes) is assigned a type of double.


16-bit:  Removing Arguments from the Stack

The following form of the auxiliary pragma specifies who removes from the stack arguments that were pushed on the stack.

     #pragma aux sym parm (caller | routine) [;]

where

description

sym

is a function name.

"caller" specifies that the caller will pop the arguments from the stack; "routine" specifies that the called routine will pop the arguments from the stack.  If "caller" or "routine" is omitted, "routine" is assumed unless the default has been changed in a previous auxiliary pragma, in which case the new default is assumed.


16-bit:  Passing Arguments in Reverse Order

The following form of the auxiliary pragma specifies that arguments are passed in the reverse order.

     #pragma aux sym parm reverse [;]

where

description

sym

is a function name.

Normally, arguments are processed from left to right.  The leftmost arguments are passed in registers and the rightmost arguments are passed on the stack (if the registers used for argument passing have been exhausted).  Arguments that are passed on the stack are pushed from right to left.

When arguments are reversed, the rightmost arguments are passed in registers and the leftmost arguments are passed on the stack (if the registers used for argument passing have been exhausted).  Arguments that are passed on the stack are pushed from left to right.

Reversing arguments is most useful for functions that require arguments to be passed on the stack in an order opposite from the default.  The following auxiliary pragma demonstrates such a function.

     #pragma aux rtn parm reverse [];


16-bit:  Describing Function Return Information

Using auxiliary pragmas, you can describe the way functions are to return values.  This is particularly useful when interfacing to functions that have been compiled by other compilers or functions written in other programming languages.

The general form of an auxiliary pragma that describes the way a function returns its value is the following.

     #pragma aux sym value {no8087 | reg_set | struct_info} [;]

     struct_info ::= struct {float | struct | (routine | caller) | reg_set}

where

description

sym

is a function name.

reg_set

is called a register set.  The register sets specify the registers that are to be used for argument passing.  A register set is a list of registers separated by spaces and enclosed in square brackets.


16-bit:  Returning Function Values in Registers

The following form of the auxiliary pragma can be used to specify the registers that are to be used to return a function's value.

     #pragma aux sym value reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

Note that the method described below for returning values of type float or double is supported only when the "fpc" option is used.

Depending on the type of the return value, only certain registers are allowed in reg_set.

1-byte

For 1-byte return values, only the following registers are allowed:  AL, AH, DL, DH, BL, BH, CL or CH.  If no register set is specified, register AL will be used.

2-byte

For 2-byte return values, only the following registers are allowed:  AX, DX, BX, CX, SI or DI.  If no register set is specified, register AX will be used.

4-byte

For 4-byte return values (except far pointers), only the following register pairs are allowed:  DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX or BX:AX.  If no register set is specified, registers DX:AX will be used.  This form of the auxiliary pragma is legal for functions of type float when using the "fpc" option only.

far pointer

For functions that return far pointers, the following register pairs are allowed:  DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX, BX:AX, DS:CX, DS:DX, DS:DI, DS:SI, DS:BX, DS:AX, ES:CX, ES:DX, ES:DI, ES:SI, ES:BX or ES:AX.  If no register set is specified, the registers DX:AX will be used.

8-byte

For 8-byte return values (including functions of type double), only the following register combination is allowed:  AX:BX:CX:DX.  If no register set is specified, the registers AX:BX:CX:DX will be used.  This form of the auxiliary pragma is legal for functions of type double when using the "fpc" option only.

Notes:

1.	An empty register set is not allowed.

2.	If you are compiling for a memory model which has a small data model, any of the above register combinations containing register DS becomes illegal.  In a small data model, segment register DS must remain unchanged as it points to the program's data segment.


16-bit:  Returning Structures

Typically, structures are not returned in registers.  Instead, the caller allocates space on the stack for the return value and sets register SI to point to it.  The called routine then places the return value at the location pointed to by register SI.

The following form of the auxiliary pragma can be used to specify the register that is to be used to point to the return value.

     #pragma aux sym value struct (caller|routine) reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

"caller" specifies that the caller will allocate memory for the return value.  The address of the memory allocated for the return value is placed in the register specified in the register set by the caller before the function is called.  If an empty register set is specified, the address of the memory allocated for the return value will be pushed on the stack immediately before the call and will be returned in register AX by the called routine.  It is assumed that the memory for the return value is allocated from the stack segment (the stack segment is contained in segment register SS).

"routine" specifies that the called routine will allocate memory for the return value.  Upon returning to the caller, the register specified in the register set will contain the address of the return value.  An empty register set is not allowed.

Only the following registers are allowed in the register set:  AX, DX, BX, CX, SI or DI.  Note that in a big data model, the address in the return register is assumed to be in the segment specified by the value in the SS segment register.

If the size of the structure being returned is 1, 2 or 4 bytes, it will be returned in registers.  The return register will be selected from the register set in the following way.

1.	A 1-byte structure will be returned in one of the following registers:  AL, AH, DL, DH, BL, BH, CL or CH.  If no register set is specified, register AL will be used.

2.	A 2-byte structure will be returned in one of the following registers:  AX, DX, BX, CX, SI or DI.  If no register set is specified, register AX will be used.

3.	A 4-byte structure will be returned in one of the following register pairs:  DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX or BX:AX.  If no register set is specified, register pair DX:AX will be used.

The following form of the auxiliary pragma can be used to specify that structures whose size is 1, 2 or 4 bytes are not to be returned in registers.  Instead, the caller will allocate space on the stack for the structure return value and point register SI to it.

     #pragma aux sym value struct struct [;]

where

description

sym

is a function name.


16-bit:  Returning Floating-Point Data

There are a few ways available for specifying how the value for a function whose type is float or double is to be returned.

The following form of the auxiliary pragma can be used to specify that function return values whose type is float or double are not to be returned in registers.  Instead, the caller will allocate space on the stack for the return value and point register SI to it.

     #pragma aux sym value struct float [;]

where

description

sym

is a function name.

In other words, floating-point values are to be returned in the same way structures are returned.

The following form of the auxiliary pragma can be used to specify that function return values whose type is float or double are not to be returned in 80x87 registers when compiling with the "fpi" or "fpi87" option.  Instead, the value will be returned in 80x86 registers.  This is the default behaviour for the "fpc" option.  Function return values whose type is float will be returned in registers DX:AX.  Function return values whose type is double will be returned in registers AX:BX:CX:DX.  This is the default method for the "fpc" option.

     #pragma aux sym value no8087 [;]

where

description

sym

is a function name.

The following form of the auxiliary pragma can be used to specify that function return values whose type is float or double are to be returned in ST(0) when compiling with the "fpi" or "fpi87" option.  This form of the auxiliary pragma is not legal for the "fpc" option.

     #pragma aux sym value [8087] [;]

where

description

sym

is a function name.


16-bit:  A Function that Never Returns

The following form of the auxiliary pragma can be used to describe a function that does not return to the caller.

     #pragma aux sym aborts [;]

where

description

sym

is a function name.

Consider the following example.

     #pragma aux exitrtn aborts;

     extern void exitrtn(void);

     void rtn()

       {

         exitrtn();

       }

exitrtn is defined to be a function that does not return.  For example, it may call exit to return to the system.  In this case, Open Watcom C/C++ generates a "jmp" instruction instead of a "call" instruction to invoke exitrtn.


16-bit:  Describing How Functions Use Memory

The following form of the auxiliary pragma can be used to describe a function that does not modify any memory (i.e., global or static variables) that is used directly or indirectly by the caller.

     #pragma aux sym modify nomemory [;]

where

description

sym

is a function name.

Consider the following example.

     #pragma off (check_stack);

     extern void myrtn(void);

     int i = { 1033 };

     extern Rtn() {

         while( i < 10000 ) {

             i += 383;

         }

         myrtn();

         i += 13143;

     };

To compile the above program, "rtn.c", we issue the following command.

     C>wcc rtn /oai /d1

     C>wpp rtn /oai /d1

     C>wcc386 rtn /oai /d1

     C>wpp386 rtn /oai /d1

For illustrative purposes, we omit loop optimizations from the list of code optimizations that we want the compiler to perform.  The "d1" compiler option is specified so that the object file produced by Open Watcom C/C++ contains source line information.

We can generate a file containing a disassembly of rtn.obj by issuing the following command.

     C>wdis rtn /l /s /r

The "s" option is specified so that the listing file produced by the Open Watcom Disassembler contains source lines taken from rtn.c.  The listing file rtn.lst appears as follows.

     Module: rtn.c

     Group: 'DGROUP' CONST,_DATA

     Segment: '_TEXT' BYTE  0026 bytes

     #pragma off (check_stack);

     extern void MyRtn( void );

     int i = { 1033 };

     extern Rtn()

       {

      0000  52                Rtn_            push    DX

      0001  8b 16 00 00                       mov     DX,_i

         while( i < 10000 ) {

      0005  81 fa 10 27       L1              cmp     DX,2710H

      0009  7d 06                             jge     L2

             i += 383;

         }

      000b  81 c2 7f 01                       add     DX,017fH

      000f  eb f4                             jmp     L1

         MyRtn();

      0011  89 16 00 00       L2              mov     _i,DX

      0015  e8 00 00                          call    MyRtn_

      0018  8b 16 00 00                       mov     DX,_i

         i += 13143;

      001c  81 c2 57 33                       add     DX,3357H

      0020  89 16 00 00                       mov     _i,DX

       };

      0024  5a                                pop     DX

      0025  c3                                ret

     No disassembly errors

     ------------------------------------------------------------

     Segment: '_DATA' WORD  0002 bytes

      0000  09 04                   _i              - ..

     No disassembly errors

     ------------------------------------------------------------

Let us add the following auxiliary pragma to the source file.

     #pragma aux myrtn modify nomemory;

If we compile the source file with the above pragma and disassemble the object file using the Open Watcom Disassembler, we get the following listing file.

     Module: rtn.c

     Group: 'DGROUP' CONST,_DATA

     Segment: '_TEXT' BYTE  0022 bytes

     #pragma off (check_stack);

     extern void MyRtn( void );

     #pragma aux MyRtn modify nomemory;

     int i = { 1033 };

     extern Rtn()

       {

      0000  52                Rtn_            push    DX

      0001  8b 16 00 00                       mov     DX,_i

         while( i < 10000 ) {

      0005  81 fa 10 27       L1              cmp     DX,2710H

      0009  7d 06                             jge     L2

             i += 383;

         }

      000b  81 c2 7f 01                       add     DX,017fH

      000f  eb f4                             jmp     L1

         MyRtn();

      0011  89 16 00 00       L2              mov     _i,DX

      0015  e8 00 00                          call    MyRtn_

         i += 13143;

      0018  81 c2 57 33                       add     DX,3357H

      001c  89 16 00 00                       mov     _i,DX

       };

      0020  5a                                pop     DX

      0021  c3                                ret

     No disassembly errors

     ------------------------------------------------------------

     Segment: '_DATA' WORD  0002 bytes

      0000  09 04                   _i              - ..

     No disassembly errors

     ------------------------------------------------------------

Notice that the value of i is in register DX after completion of the "while" loop.  After the call to myrtn, the value of i is not loaded from memory into a register to perform the final addition.  The auxiliary pragma informs the compiler that myrtn does not modify any memory (i.e., global or static variables) that is used directly or indirectly by Rtn and hence register DX contains the correct value of i.

The preceding auxiliary pragma deals with routines that modify memory.  Let us consider the case where routines reference memory.  The following form of the auxiliary pragma can be used to describe a function that does not reference any memory (i.e., global or static variables) that is used directly or indirectly by the caller.

     #pragma aux sym parm nomemory modify nomemory [;]

where

description

sym

is a function name.

Notes:

1.	You must specify both "parm nomemory" and "modify nomemory".

Let us replace the auxiliary pragma in the above example with the following auxiliary pragma.

     #pragma aux myrtn parm nomemory modify nomemory;

If you now compile our source file and disassemble the object file using WDIS, the result is the following listing file.

     Module: rtn.c

     Group: 'DGROUP' CONST,_DATA

     Segment: '_TEXT' BYTE  001e bytes

     #pragma off (check_stack);

     extern void MyRtn( void );

     #pragma aux MyRtn parm nomemory modify nomemory;

     int i = { 1033 };

     extern Rtn()

       {

      0000  52                Rtn_            push    DX

      0001  8b 16 00 00                       mov     DX,_i

         while( i < 10000 ) {

      0005  81 fa 10 27       L1              cmp     DX,2710H

      0009  7d 06                             jge     L2

             i += 383;

         }

      000b  81 c2 7f 01                       add     DX,017fH

      000f  eb f4                             jmp     L1

         MyRtn();

      0011  e8 00 00          L2              call    MyRtn_

         i += 13143;

      0014  81 c2 57 33                       add     DX,3357H

      0018  89 16 00 00                       mov     _i,DX

       };

      001c  5a                                pop     DX

      001d  c3                                ret

     No disassembly errors

     ------------------------------------------------------------

     Segment: '_DATA' WORD  0002 bytes

      0000  09 04                   _i              - ..

     No disassembly errors

     ------------------------------------------------------------

Notice that after completion of the "while" loop we did not have to update i with the value in register DX before calling myrtn.  The auxiliary pragma informs the compiler that myrtn does not reference any memory (i.e., global or static variables) that is used directly or indirectly by myrtn so updating i was not necessary before calling myrtn.


16-bit:  Describing the Registers Modified by a Function

The following form of the auxiliary pragma can be used to describe the registers that a function will use without saving.

     #pragma aux sym modify [exact] reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

Specifying a register set informs Open Watcom C/C++ that the registers belonging to the register set are modified by the function.  That is, the value in a register before calling the function is different from its value after execution of the function.

Registers that are used to pass arguments are assumed to be modified and hence do not have to be saved and restored by the called function.  Also, since the AX register is frequently used to return a value, it is always assumed to be modified.  If necessary, the caller will contain code to save and restore the contents of registers used to pass arguments.  Note that saving and restoring the contents of these registers may not be necessary if the called function does not modify them.  The following form of the auxiliary pragma can be used to describe exactly those registers that will be modified by the called function.

     #pragma aux sym modify exact reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

The above form of the auxiliary pragma tells Open Watcom C/C++ not to assume that the registers used to pass arguments will be modified by the called function.  Instead, only the registers specified in the register set will be modified.  This will prevent generation of the code which unnecessarily saves and restores the contents of the registers used to pass arguments.

Also, any registers that are specified in the value register set are assumed to be unmodified unless explicitly listed in the exact register set.  In the following example, the code generator will not generate code to save and restore the value of the stack pointer register since we have told it that "GetSP" does not modify any register whatsoever.

Example:

     unsigned GetSP(void);

     #if defined(__386__)

     #pragma aux GetSP = value [esp] modify exact [];

     #else

     #pragma aux GetSP = value [sp] modify exact [];

     #endif


16-bit:  An Example

As mentioned in an earlier section, the following pragma defines the calling convention for functions compiled by Microsoft C.

     #pragma aux MS_C "_*"                                  \

                      parm caller []                        \

                      value struct float struct routine [ax]\

                      modify [ax bx cx dx es];

Let us discuss this pragma in detail.

"_*"

specifies that all function and variable names are preceded by the underscore character (_) when translated from source form to object form.

parm caller []

specifies that all arguments are to be passed on the stack (an empty register set was specified) and the caller will remove the arguments from the stack.

value struct

marks the section describing how the called routine returns structure information.

float

specifies that floating-point arguments are returned in the same way as structures are returned.

struct

specifies that 1, 2 and 4-byte structures are not to be returned in registers.

routine

specifies that the called routine allocates storage for the return structure and returns with a register pointing at it.

[ax]

specifies that register AX is used to point to the structure return value.

modify [ax bx cx dx es]

specifies that registers AX, BX, CX, DX and ES are not preserved by the called routine.

Note that the default method of returning integer values is used; 1-byte characters are returned in register AL, 2-byte integers are returned in register AX, and 4-byte integers are returned in the register pair DX:AX.


16-bit:  Auxiliary Pragmas and the 80x87

This section deals with those aspects of auxiliary pragmas that are specific to the 80x87.  The discussion in this chapter assumes that one of the "fpi" or "fpi87" options is used to compile functions.  The following areas are affected by the use of these options.

1.	passing floating-point arguments to functions,

2.	returning floating-point values from functions and

3.	which 80x87 floating-point registers are allowed to be modified by the called routine.


16-bit:  Using the 80x87 to Pass Arguments

By default, floating-point arguments are passed on the 80x86 stack.  The 80x86 registers are never used to pass floating-point arguments when a function is compiled with the "fpi" or "fpi87" option.  However, they can be used to pass arguments whose type is not floating-point such as arguments of type "int".

The following form of the auxiliary pragma can be used to describe the registers that are to be used to pass arguments to functions.

     #pragma aux sym parm {reg_set} [;]

where

description

sym

is a function name.

reg_set

is a register set.  The register set can contain 80x86 registers and/or the string "8087".

Notes:

1.	If an empty register set is specified, all arguments, including floating-point arguments, will be passed on the 80x86 stack.

When the string "8087" appears in a register set, it simply means that floating-point arguments can be passed in 80x87 floating-point registers if the source file is compiled with the "fpi" or "fpi87" option.  Before discussing argument passing in detail, some general notes on the use of the 80x87 floating-point registers are given.

The 80x87 contains 8 floating-point registers which essentially form a stack.  The stack pointer is called ST and is a number between 0 and 7 identifying which 80x87 floating-point register is at the top of the stack.  ST is initially 0.  80x87 instructions reference these registers by specifying a floating-point register number.  This number is then added to the current value of ST.  The sum (taken modulo 8) specifies the 80x87 floating-point register to be used.  The notation ST(n), where "n" is between 0 and 7, is used to refer to the position of an 80x87 floating-point register relative to ST.

When a floating-point value is loaded onto the 80x87 floating-point register stack, ST is decremented (modulo 8), and the value is loaded into ST(0).  When a floating-point value is stored and popped from the 80x87 floating-point register stack, ST is incremented (modulo 8) and ST(1) becomes ST(0).  The following illustrates the use of the 80x87 floating-point registers as a stack, assuming that the value of ST is 4 (4 values have been loaded onto the 80x87 floating-point register stack).

                 +----------------+

           0     | 4th from top   |  ST(4)

                 +----------------+

           1     | 5th from top   |  ST(5)

                 +----------------+

           2     | 6th from top   |  ST(6)

                 +----------------+

           3     | 7th from top   |  ST(7)

                 +----------------+

     ST -> 4     | top of stack   |  ST(0)

                 +----------------+

           5     | 1st from top   |  ST(1)

                 +----------------+

           6     | 2nd from top   |  ST(2)

                 +----------------+

           7     | 3rd from top   |  ST(3)

                 +----------------+

Starting with version 9.5, the Open Watcom compilers use all eight of the 80x87 registers as a stack.  The initial state of the 80x87 register stack is empty before a program begins execution.

Note:

For compatibility with code compiled with version 9.0 and earlier, you can compile with the "fpr" option.  In this case only four of the eight 80x87 registers are used as a stack.  These four registers were used to pass arguments.  The other four registers form what was called the 80x87 cache.  The cache was used for local floating-point variables.  The state of the 80x87 registers before a program began execution was as follows.

1.	The four 80x87 floating-point registers that form the stack are uninitialized.

2.	The four 80x87 floating-point registers that form the 80x87 cache are initialized with zero.

Hence, initially the 80x87 cache was comprised of ST(0), ST(1), ST(2) and ST(3).  ST had the value 4 as in the above diagram.  When a floating-point value was pushed on the stack (as is the case when passing floating-point arguments), it became ST(0) and the 80x87 cache was comprised of ST(1), ST(2), ST(3) and ST(4).  When the 80x87 stack was full, ST(0), ST(1), ST(2) and ST(3) formed the stack and ST(4), ST(5), ST(6) and ST(7) formed the 80x87 cache.  Version 9.5 and later no longer use this strategy.

The rules for passing arguments are as follows.

1.	If the argument is not floating-point, use the procedure described earlier in this chapter.

2.	If the argument is floating-point, and a previous argument has been assigned a position on the 80x86 stack (instead of the 80x87 stack), the floating-point argument is also assigned a position on the 80x86 stack.  Otherwise proceed to the next step.

3.	If the string "8087" appears in a register set in the pragma, and if the 80x87 stack is not full, the floating-point argument is assigned floating-point register ST(0) (the top element of the 80x87 stack).  The previous top element (if there was one) is now in ST(1).  Since arguments are pushed on the stack from right to left, the leftmost floating-point argument will be in ST(0).  Otherwise the floating-point argument is assigned a position on the 80x86 stack.

Consider the following example.

     #pragma aux myrtn parm [8087];

     void main()

     {

         float    x;

         double   y;

         int      i;

         long int j;

         x = 7.7;

         i = 7;

         y = 77.77;

         j = 77;

         myrtn( x, i, y, j );

     }

myrtn is an assembly language function that requires four arguments.  The first argument of type float (4 bytes), the second argument is of type int (2 bytes), the third argument is of type double (8 bytes) and the fourth argument is of type long int (4 bytes).  These arguments will be passed to myrtn in the following way.

1.	Since "8087" was specified in the register set, the first argument, being of type float, will be passed in an 80x87 floating-point register.

2.	The second argument will be passed on the stack since no 80x86 registers were specified in the register set.

3.	The third argument will also be passed on the stack.  Remember the following rule:  once an argument is assigned a position on the stack, all remaining arguments will be assigned a position on the stack.  Note that the above rule holds even though there are some 80x87 floating-point registers available for passing floating-point arguments.

4.	The fourth argument will also be passed on the stack.

Let us change the auxiliary pragma in the above example as follows.

     #pragma aux myrtn parm [ax 8087];

The arguments will now be passed to myrtn in the following way.

1.	Since "8087" was specified in the register set, the first argument, being of type float will be passed in an 80x87 floating-point register.

2.	The second argument will be passed in register AX, exhausting the set of available 80x86 registers for argument passing.

3.	The third argument, being of type double, will also be passed in an 80x87 floating-point register.

4.	The fourth argument will be passed on the stack since no 80x86 registers remain in the register set.


16-bit:  Using the 80x87 to Return Function Values

The following form of the auxiliary pragma can be used to describe a function that returns a floating-point value in ST(0).

     #pragma aux sym value reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set containing the string "8087", i.e.  [8087].


16-bit:  Preserving 80x87 Floating-Point Registers Across Calls

The code generator assumes that all eight 80x87 floating-point registers are available for use within a function unless the "fpr" option is used to generate backward compatible code (older Open Watcom compilers used four registers as a cache).  The following form of the auxiliary pragma specifies that the floating-point registers in the 80x87 cache may be modified by the specified function.

     #pragma aux sym modify reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set containing the string "8087", i.e.  [8087].

This instructs Open Watcom C/C++ to save any local variables that are located in the 80x87 cache before calling the specified routine.


32-bit Memory Models

This chapter describes the various 32-bit memory models supported by Open Watcom C/C++.  Each memory model is distinguished by two properties; the code model used to implement function calls and the data model used to reference data.


32-bit Code Models

There are two code models;

1.	the small code model and

2.	the big code model.

A small code model is one in which all calls to functions are made with near calls.  In a near call, the destination address is 32 bits and is relative to the segment value in segment register CS.  Hence, in a small code model, all code comprising your program, including library functions, must be less than 4GB.

A big code model is one in which all calls to functions are made with far calls.  In a far call, the destination address is 48 bits (a 16-bit segment value and a 32-bit offset relative to the segment value).  This model allows the size of the code comprising your program to exceed 4GB.

  Note:  If your program contains less than 4GB of code, you should use a memory model that employs the small code model.  This will result in smaller and faster code since near calls are smaller instructions and are processed faster by the CPU.


32-bit Data Models

There are two data models;

1.	the small data model and

2.	the big data model.

A small data model is one in which all references to data are made with near pointers.  Near pointers are 32 bits; all data references are made relative to the segment value in segment register DS.  Hence, in a small data model, all data comprising your program must be less than 4GB.

A big data model is one in which all references to data are made with far pointers.  Far pointers are 48 bits (a 16-bit segment value and a 32-bit offset relative to the segment value).  This removes the 4GB limitation on data size imposed by the small data model.  However, when a far pointer is incremented, only the offset is adjusted.  Open Watcom C/C++ assumes that the offset portion of a far pointer will not be incremented beyond 4GB.  The compiler will assign an object to a new segment if the grouping of data in a segment will cause the object to cross a segment boundary.  Implicit in this is the requirement that no individual object exceed 4GB.

  Note:  If your program contains less than 4GB of data, you should use the small data model.  This will result in smaller and faster code since references using near pointers produce fewer instructions.


Summary of 32-bit Memory Models

As previously mentioned, a memory model is a combination of a code model and a data model.  The following table describes the memory models supported by Open Watcom C/C++.

     Memory      Code        Data        Default     Default

     Model       Model       Model       Code        Data

                                         Pointer     Pointer

     --------    --------    --------    --------    --------

     flat        small       small       near        near

     small       small       small       near        near

     medium      big         small       far         near

     compact     small       big         near        far

     large       big         big         far         far


Flat Memory Model

In the flat memory model, the application's code and data must total less than 4GB in size.  Segment registers CS, DS, SS and ES point to the same linear address space (this does not imply that the segment registers contain the same value).  That is, a given offset in one segment refers to the same memory location as that offset in another segment.  Essentially, a flat model operates as if there were no segments.


Mixed 32-bit Memory Model

A mixed memory model application combines elements from the various code and data models.  A mixed memory model application might be characterized as one that uses the near , far , or huge keywords when describing some of its functions or data objects.

For example, a medium memory model application that uses some far pointers to data can be described as a mixed memory model.  In an application such as this, most of the data is in a 4GB segment (DGROUP) and hence can be referenced with near pointers relative to the segment value in segment register DS.  This results in more efficient code being generated and better execution times than one can expect from a big data model.  Data objects outside of the DGROUP segment are described with the far keyword.


Linking Applications for the Various 32-bit Memory Models

Each memory model requires different run-time and floating-point libraries.  Each library assumes a particular memory model and should be linked only with modules that have been compiled with the same memory model.  The following table lists the libraries that are to be used to link an application that has been compiled for a particular memory model.  Currently, only libraries for the flat/small memory model are provided.

     Memory      Run-time    Floating-Point   Floating-Point

     Model       Library     Library (80x87)  Library (f-p calls)

     ----------  ----------  ---------------  -------------------

     flat/small  CLIB3R.LIB    MATH387R.LIB     MATH3R.LIB

                 CLIB3S.LIB    MATH387S.LIB     MATH3S.LIB

                 PLIB3R.LIB    CPLX73R.LIB      CPLX3R.LIB

                 PLIB3S.LIB    CPLX73S.LIB      CPLX3S.LIB

The letter "R" or "S" which is affixed to the file name indicates the particular strategy with which the modules in the library have been compiled.

R

denotes a version of the Open Watcom C/C++ 32-bit libraries which have been compiled for the "flat/small" memory models using the "3r", "4r" or "5r" option.

S

denotes a version of the Open Watcom C/C++ 32-bit libraries which have been compiled for the "flat/small" memory models using the "3s", "4s" or "5s" option.


32-bit Memory Layout

The following describes the segment ordering of an application linked by the Open Watcom Linker.  Note that this assumes that the "DOSSEG" linker option has been specified.

1.	all "USE16" segments.  These segments are present in applications that execute in both real mode and protected mode.  They are first in the segment ordering so that the "REALBREAK" option of the "RUNTIME" directive can be used to separate the real-mode part of the application from the protected-mode part of the application.  Currently, the "RUNTIME" directive is valid for Phar Lap executables only.

2.	all segments not belonging to group "DGROUP" with class "CODE"

3.	all other segments not belonging to group "DGROUP"

4.	all segments belonging to group "DGROUP" with class "BEGDATA"

5.	all segments belonging to group "DGROUP" not with class "BEGDATA", "BSS" or "STACK"

6.	all segments belonging to group "DGROUP" with class "BSS"

7.	all segments belonging to group "DGROUP" with class "STACK"

Segments belonging to class "BSS" contain uninitialized data.  Note that this only includes uninitialized data in segments belonging to group "DGROUP".  Segments belonging to class "STACK" are used to define the size of the stack used for your application.  Segments belonging to the classes "BSS" and "STACK" are last in the segment ordering so that uninitialized data need not take space in the executable file.

In addition to these special segments, the following conventions are used by Open Watcom C/C++.

1.	The "CODE" class contains the executable code for your application.  In a small code model, this consists of the segment "_TEXT".  In a big code model, this consists of the segments "<module>_TEXT" where <module> is the file name of the source file.

2.	The "FAR_DATA" class consists of the following:

(a)

data objects whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(b)

data objects defined using the "FAR" or "HUGE" keyword,

(c)

literals whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(d)

literals defined using the "FAR" or "HUGE" keyword.

You can override the default naming convention used by Open Watcom C/C++ to name segments.

1.	The Open Watcom C/C++ "nm" option can be used to change the name of the module.  This, in turn, changes the name of the code segment when compiling for a big code model.

2.	The Open Watcom C/C++ "nt" option can be used to specify the name of the code segment regardless of the code model used.


32-bit Assembly Language Considerations

This chapter will deal with the following topics.

1.	The data representation of the basic types supported by Open Watcom C/C++.

2.	The memory layout of a Open Watcom C/C++ program.

3.	The method for passing arguments and returning values.

4.	The two methods for passing floating-point arguments and returning floating-point values.

One method is used when one of the Open Watcom C/C++ "fpi" or "fpi87" options is specified for the generation of in-line 80x87 instructions.  When the "fpi" option is specified, an 80x87 emulator is included from a math library if the application includes floating-point operations.  When the "fpi87" option is used exclusively, the 80x87 emulator will not be included.

The other method is used when the Open Watcom C/C++ "fpc" option is specified.  In this case, the compiler generates calls to floating-point support routines in the alternate math libraries.

An understanding of the Intel 80x86 architecture is assumed.


32-bit:  Data Representation

This section describes the internal or machine representation of the basic types supported by Open Watcom C/C++.


32-bit:  Type "char"

An item of type "char" occupies 1 byte of storage.  Its value is in the following range.

     0 <= n <= 255

Note that "char" is, by default, unsigned.  The Open Watcom C/C++ compiler option "j" can be used to change the default from unsigned to signed.  If "char" is signed, an item of type "char" is in the following range.

     -128 <= n <= 127

You can force an item of type "char" to be unsigned or signed regardless of the default by defining them to be of type "unsigned char" or "signed char" respectively.


32-bit:  Type "short int"

An item of type "short int" occupies 2 bytes of storage.  Its value is in the following range.

     -32768 <= n <= 32767

Note that "short int" is signed and hence "short int" and "signed short int" are equivalent.  If an item of type "short int" is to be unsigned, it must be defined as "unsigned short int".  In this case, its value is in the following range.

     0 <= n <= 65535


32-bit:  Type "long int"

An item of type "long int" occupies 4 bytes of storage.  Its value is in the following range.

     -2147483648 <= n <= 2147483647

Note that "long int" is signed and hence "long int" and "signed long int" are equivalent.  If an item of type "long int" is to be unsigned, it must be defined as "unsigned long int".  In this case, its value is in the following range.

     0 <= n <= 4294967295


32-bit:  Type "int"

An item of type "int" occupies 4 bytes of storage.  Its value is in the following range.

     -2147483648 <= n <= 2147483647

Note that "int" is signed and hence "int" and "signed int" are equivalent.  If an item of type "int" is to be unsigned, it must be defined as "unsigned int".  In this case its value is in the following range.

     0 <= n <= 4294967295

If you are generating code that executes in 32-bit mode, "long int" and "int" are equivalent, "unsigned long int" and "unsigned int" are equivalent, and "signed long int" and "signed int" are equivalent.  This may not be the case in other environments where "int" and "short int" are 2 bytes.


32-bit:  Type "float"

A datum of type "float" is an approximate representation of a real number.  Each datum of type "float" occupies 4 bytes.  If m is the magnitude of x (an item of type "float") then x can be approximated if

      -126           128

     2      <= m <  2

or in more approximate terms if

     1.175494e-38 <= m <= 3.402823e38

Data of type "float" are represented internally as follows.  Note that bytes are stored in memory with the least significant byte first and the most significant byte last.

     +---+---------+---------------------+

     | S | Biased  |      Significand    |

     |   | Exponent|                     |

     +---+---------+---------------------+

      31    30-23           22-0

Notes

S

S = Sign bit (0=positive, 1=negative)

Exponent

The exponent bias is 127 (i.e., exponent value 1 represents 2**-126; exponent value 127 represents 2**0; exponent value 254 represents 2**127; etc.).  The exponent field is 8 bits long.

Significand

The leading bit of the significand is always 1, hence it is not stored in the significand field.  Thus the significand is always "normalized".  The significand field is 23 bits long.

Zero

A real zero quantity occurs when the sign bit, exponent, and significand are all zero.

Infinity

When the exponent field is all 1 bits and the significand field is all zero bits then the quantity represents positive or negative infinity, depending on the sign bit.

Not Numbers

When the exponent field is all 1 bits and the significand field is non-zero then the quantity is a special value called a NAN (Not-A-Number).

When the exponent field is all 0 bits and the significand field is non-zero then the quantity is a special value called a "denormal" or nonnormal number.


32-bit:  Type "double"

A datum of type "double" is an approximate representation of a real number.  The precision of a datum of type "double" is greater than or equal to one of type "float".  Each datum of type "double" occupies 8 bytes.  If m is the magnitude of x (an item of type "double") then x can be approximated if

      -1022          1024

     2      <= m <  2

or in more approximate terms if

     2.2250738585072e-308 <= m <= 1.79769313486232e308

Data of type "double" are represented internally as follows.  Note that bytes are stored in memory with the least significant byte first and the most significant byte last.

     +---+---------+--------------------------------------+

     | S | Biased  |              Significand             |

     |   | Exponent|                                      |

     +---+---------+--------------------------------------+

      63    62-52                   51-0

Notes:

S

S = Sign bit (0=positive, 1=negative)

Exponent

The exponent bias is 1023 (i.e., exponent value 1 represents 2**-1022; exponent value 1023 represents 2**0; exponent value 2046 represents 2**1023; etc.).  The exponent field is 11 bits long.

Significand

The leading bit of the significand is always 1, hence it is not stored in the significand field.  Thus the significand is always "normalized".  The significand field is 52 bits long.

Zero

A double precision zero quantity occurs when the sign bit, exponent, and significand are all zero.

Infinity

When the exponent field is all 1 bits and the significand field is all zero bits then the quantity represents positive or negative infinity, depending on the sign bit.

Not Numbers

When the exponent field is all 1 bits and the significand field is non-zero then the quantity is a special value called a NAN (Not-A-Number).

When the exponent field is all 0 bits and the significand field is non-zero then the quantity is a special value called a "denormal" or nonnormal number.


32-bit:  Memory Layout

The following describes the segment ordering of an application linked by the Open Watcom Linker.  Note that this assumes that the "DOSSEG" linker option has been specified.

1.	all "USE16" segments.  These segments are present in applications that execute in both real mode and protected mode.  They are first in the segment ordering so that the "REALBREAK" option of the "RUNTIME" directive can be used to separate the real-mode part of the application from the protected-mode part of the application.  Currently, the "RUNTIME" directive is valid for Phar Lap executables only.

2.	all segments not belonging to group "DGROUP" with class "CODE"

3.	all other segments not belonging to group "DGROUP"

4.	all segments belonging to group "DGROUP" with class "BEGDATA"

5.	all segments belonging to group "DGROUP" not with class "BEGDATA", "BSS" or "STACK"

6.	all segments belonging to group "DGROUP" with class "BSS"

7.	all segments belonging to group "DGROUP" with class "STACK"

Segments belonging to class "BSS" contain uninitialized data.  Note that this only includes uninitialized data in segments belonging to group "DGROUP".  Segments belonging to class "STACK" are used to define the size of the stack used for your application.  Segments belonging to the classes "BSS" and "STACK" are last in the segment ordering so that uninitialized data need not take space in the executable file.

In addition to these special segments, the following conventions are used by Open Watcom C/C++.

1.	The "CODE" class contains the executable code for your application.  In a small code model, this consists of the segment "_TEXT".  In a big code model, this consists of the segments "<module>_TEXT" where <module> is the file name of the source file.

2.	The "FAR_DATA" class consists of the following:

(a)

data objects whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(b)

data objects defined using the "FAR" or "HUGE" keyword,

(c)

literals whose size exceeds the data threshold in large data memory models (the data threshold is 32K unless changed using the "zt" compiler option)

(d)

literals defined using the "FAR" or "HUGE" keyword.

You can override the default naming convention used by Open Watcom C/C++ to name segments.

1.	The Open Watcom C/C++ "nm" option can be used to change the name of the module.  This, in turn, changes the name of the code segment when compiling for a big code model.

2.	The Open Watcom C/C++ "nt" option can be used to specify the name of the code segment regardless of the code model used.


32-bit:  Calling Conventions for Non-80x87 Applications

The following sections describe the calling convention used when compiling with the "fpc" compiler option.


32-bit:  Passing Arguments Using Register-Based Calling Conventions

How arguments are passed to a function with register-based calling conventions is determined by the size (in bytes) of the argument and where in the argument list the argument appears.  Depending on the size, arguments are either passed in registers or on the stack.  Arguments such as structures are almost always passed on the stack since they are generally too large to fit in registers.  Since arguments are processed from left to right, the first few arguments are likely to be passed in registers (if they can fit) and, if the argument list contains many arguments, the last few arguments are likely to be passed on the stack.

The registers used to pass arguments to a function are EAX, EBX, ECX and EDX.  The following algorithm describes how arguments are passed to functions.

Initially, we have the following registers available for passing arguments:  EAX, EDX, EBX and ECX.  Note that registers are selected from this list in the order they appear.  That is, the first register selected is EAX and the last is ECX.  For each argument Ai, starting with the left most argument, perform the following steps.

1.	If the size of Ai is 1 byte or 2 bytes, convert it to 4 bytes and proceed to the next step.  If Ai is of type "unsigned char" or "unsigned short int", it is converted to an "unsigned int".  If Ai is of type "signed char" or "signed short int", it is converted to a "signed int".  If Ai is a 1-byte or 2-byte structure, the padding is determined by the compiler.

2.	If an argument has already been assigned a position on the stack, Ai will also be assigned a position on the stack.  Otherwise, proceed to the next step.

3.	If the size of Ai is 4 bytes, select a register from the list of available registers.  If a register is available, Ai is assigned that register.  The register is then removed from the list of available registers.  If no registers are available, Ai will be assigned a position on the stack.

4.	If the type of Ai is "far pointer", select a register pair from the following list of combinations:  [EDX EAX] or [ECX EBX].  The first available register pair is assigned to Ai and removed from the list of available pairs.  The segment value will actually be passed in register DX or CX and the offset in register EAX or EBX.  If none of the above register pairs is available, Ai will be assigned a position on the stack.  Note that 8 bytes will be pushed on the stack even though the size of an item of type "far pointer" is 6 bytes.

5.	If the type of Ai is "double" or "float" (in the absence of a function prototype), select a register pair from the following list of combinations:  [EDX EAX] or [ECX EBX].  The first available register pair is assigned to Ai and removed from the list of available pairs.  The high-order 32 bits of the argument are assigned to the first register in the pair; the low-order 32 bits are assigned to the second register in the pair.  If none of the above register pairs is available, Ai will be assigned a position on the stack.

6.	All other arguments will be assigned a position on the stack.

Notes:

1.	Arguments that are assigned a position on the stack are padded to a multiple of 4 bytes.  That is, if a 3-byte structure is assigned a position on the stack, 4 bytes will be pushed on the stack.

2.	Arguments that are assigned a position on the stack are pushed onto the stack starting with the rightmost argument.


32-bit:  Sizes of Predefined Types

The following table lists the predefined types, their size as returned by the "sizeof" function, the size of an argument of that type and the registers used to pass that argument if it was the only argument in the argument list.

    Basic

Type    "sizeof"    Argument  Registers

                    Size      Used

    char      1       4       [EAX]

    short int 2       4       [EAX]

    int       4       4       [EAX]

    long int  4       4       [EAX]

    float     4       8       [EDX EAX]

    double    8       8       [EDX EAX]

    near

pointer      4       4        [EAX]

    far

pointer       6       8       [EDX EAX]

Note that the size of the argument listed in the table assumes that no function prototypes are specified.  Function prototypes affect the way arguments are passed.  This will be discussed in the section entitled "Effect of Function Prototypes on Arguments".

Notes:

1.	Provided no function prototypes exist, an argument will be converted to a default type as described in the following table.

Argument Type

Passed As

char

unsigned int

signed char

signed int

unsigned char

unsigned int

short

unsigned int

signed short

signed int

unsigned short

unsigned int

float

double


32-bit:  Size of Enumerated Types

The integral type of an enumerated type is determined by the values of the enumeration constants.  In strict ISO/ANSI C mode, all enumerated constants are of type int.  In the extensions mode, the compiler will use the smallest integral type possible (excluding long ints) that can represent all values of the enumerated type.  For instance, if the minimum and maximum values of the enumeration constants are in the range -128 and 127, the enumerated type will be equivalent to a signed char (size = 1 byte).  All references to enumerated constants in the previous instance will have type signed char.  An enumerated constant is always promoted to an int when passed as an argument.


32-bit:  Effect of Function Prototypes on Arguments

Function prototypes define the types of the formal parameters of a function.  Their appearance affects the way in which arguments are passed.  An argument will be converted to the type of the corresponding formal parameter in the function prototype.  Consider the following example.

     void prototype( float x, int i );

     void main()

     {

       float x;

       int   i;

       x = 3.14;

       i = 314;

       prototype( x, i );

       rtn( x, i );

     }

The function prototype for prototype specifies that the first argument is to be passed as a "float" and the second argument is to be passed as an "int".  This results in the first argument being passed in register EAX and the second argument being passed in register EDX.

If no function prototype is given, as is the case for the function rtn, the first argument will be passed as a "double" and the second argument would be passed as an "int".  This results in the first argument being passed in registers EDX and EAX and the second argument being passed in register EBX.

Note that even though both prototype and rtn were called with identical argument lists, the way in which the arguments were passed was completely different simply because a function prototype for prototype was specified.  Function prototyping is an excellent way to guarantee that arguments will be passed as expected to your assembly language function.


32-bit:  Interfacing to Assembly Language Functions

Consider the following example.

Example:

     void main()

     {

         double   x;

         int      i;

         double   y;

         x = 7;

         i = 77;

         y = 777;

         myrtn( x, i, y );

     }

myrtn is an assembly language function that requires three arguments.  The first argument is of type "double", the second argument is of type "int" and the third argument is again of type "double".  Using the rules for register-based calling conventions, these arguments will be passed to myrtn in the following way:

1.	The first argument will be passed in registers EDX and EAX leaving EBX and ECX as available registers for other arguments.

2.	The second argument will be passed in register EBX leaving ECX as an available register for other arguments.

3.	The third argument will not fit in register ECX (its size is 8 bytes) and hence will be pushed on the stack.

Let us look at the stack upon entry to myrtn.

     Small Code Model

     Offset

             +----------------+

       0     | return address | <- ESP points here

             +----------------+

       4     | argument #3    |

             |                |

             +----------------+

      12     |                |

     Big Code Model

     Offset

             +----------------+

       0     | return address | <- ESP points here

             |                |

             +----------------+

       8     | argument #3    |

             |                |

             +----------------+

      16     |                |

Notes:

1.	The return address is the top element on the stack.  In a small code model, the return address is 1 double word (32 bits); in a big code model, the return address is 2 double words (64 bits).

Register EBP is normally used to address arguments on the stack.  Upon entry to the function, register EBP is set to point to the stack but before doing so we must save its contents.  The following two instructions achieve this.

     push    EBP           ; save current value of EBP

     mov     EBP,ESP       ; get access to arguments

After executing these instructions, the stack looks like this.

     Small Code Model

     Offset

             +----------------+

       0     | saved EBP      | <- EBP and ESP point here

             +----------------+

       4     | return address |

             +----------------+

       8     | argument #3    |

             |                |

             +----------------+

      16     |                |

     Big Code Model

     Offset

             +----------------+

       0     | saved EBP      | <- EBP and ESP point here

             +----------------+

       4     | return address |

             |                |

             +----------------+

      12     | argument #3    |

             |                |

             +----------------+

      20     |                |

As the above diagrams show, the third argument is at offset 8 from register EBP in a small code model and offset 12 in a big code model.

Upon exit from myrtn, we must restore the value of EBP.  The following two instructions achieve this.

     mov     ESP,EBP       ; restore stack pointer

     pop     EBP           ; restore EBP

The following is a sample assembly language function which implements myrtn.

     Small Memory Model (small code, small data)

     DGROUP        group   _DATA, _BSS

     _TEXT         segment byte public 'CODE'

                   assume  CS:_TEXT

                   assume  DS:DGROUP

                   public  myrtn_

     myrtn_        proc    near

                   push    EBP

                   ; save EBP

                   mov     EBP,ESP   ; get access to arguments

     ;

     ; body of function

     ;

                   mov     ESP,EBP   ; restore ESP

                   pop     EBP

                   ; restore EBP

                   ret     8         ; return and pop last arg

     myrtn_        endp

     _TEXT         ends

     Large Memory Model (big code, big data)

     DGROUP        group   _DATA, _BSS

     MYRTN_TEXT segment byte public 'CODE'

                   assume  CS:MYRTN_TEXT

                   public  myrtn_

     myrtn_        proc    far

                   push    EBP

                   ; save EBP

                   mov     EBP,ESP   ; get access to arguments

     ;

     ; body of function

     ;

                   mov     ESP,EBP   ; restore ESP

                   pop     EBP

                   ; restore EBP

                   ret     8         ; return and pop last arg

     myrtn_        endp

     MYRTN_TEXT ends

Notes:

1.	Global function names must be followed with an underscore.  Global variable names must be preceded with an underscore.

2.	All used 80x86 registers must be saved on entry and restored on exit except those used to pass arguments and return values, and AX, which is considered a stratch register.  Note that segment registers only have to saved and restored if you are compiling your application with the "r" option.

3.	The direction flag must be clear before returning to the caller.

4.	In a small code model, any segment containing executable code must belong to the segment "_TEXT" and the class "CODE".  The segment "_TEXT" must have a "combine" type of "PUBLIC".  On entry, CS contains the segment address of the segment "_TEXT".  In a big code model there is no restriction on the naming of segments which contain executable code.

5.	In a small data model, segment register DS contains the segment address of the group "DGROUP".  This is not the case in a big data model.

6.	When writing assembly language functions for the small code model, you must declare them as "near".  If you wish to write assembly language functions for the big code model, you must declare them as "far".

7.	In general, when naming segments for your code or data, you should follow the conventions described in the section entitled "Memory Layout" in this chapter.

8.	If any of the arguments was pushed onto the stack, the called routine must pop those arguments off the stack in the "ret" instruction.


32-bit:  Using Stack-Based Calling Conventions

Let us now consider the example in the previous section except this time we will use the stack-based calling convention.  The most significant difference between the stack-based calling convention and the register-based calling convention is the way the arguments are passed.  When using the stack-based calling conventions, no registers are used to pass arguments.  Instead, all arguments are passed on the stack.

Let us look at the stack upon entry to myrtn.

     Small Code Model

     Offset

             +----------------+

       0     | return address | <- ESP points here

             +----------------+

       4     | argument #1    |

             |                |

             +----------------+

      12     | argument #2    |

             |                |

             +----------------+

      16     | argument #3    |

             |                |

             +----------------+

      24     |                |

     Big Code Model

     Offset

             +----------------+

       0     | return address | <- ESP points here

             |                |

             +----------------+

       8     | argument #1    |

             |                |

             +----------------+

      16     | argument #2    |

             |                |

             +----------------+

      20     | argument #3    |

             |                |

             +----------------+

      28     |                |

Notes:

1.	The return address is the top element on the stack.  In a small code model, the return address is 1 double word (32 bits); in a big code model, the return address is 2 double words (64 bits).

Register EBP is normally used to address arguments on the stack.  Upon entry to the function, register EBP is set to point to the stack but before doing so we must save its contents.  The following two instructions achieve this.

     push    EBP           ; save current value of EBP

     mov     EBP,ESP       ; get access to arguments

After executing these instructions, the stack looks like this.

     Small Code Model

     Offset

             +----------------+

       0     | saved EBP      | <- EBP and ESP point here

             +----------------+

       4     | return address |

             +----------------+

       8     | argument #1    |

             |                |

             +----------------+

      16     | argument #2    |

             |                |

             +----------------+

      20     | argument #3    |

             |                |

             +----------------+

      28     |                |

     Big Code Model

     Offset

             +----------------+

       0     | saved EBP      | <- EBP and ESP point here

             +----------------+

       4     | return address |

             |                |

             +----------------+

      12     | argument #1    |

             |                |

             +----------------+

      20     | argument #2    |

             |                |

             +----------------+

      24     | argument #3    |

             |                |

             +----------------+

      32     |                |

As the above diagrams show, the argument are all on the stack and are referenced by specifying an offset from register EBP.

Upon exit from myrtn, we must restore the value of EBP.  The following two instructions achieve this.

     mov     ESP,EBP       ; restore stack pointer

     pop     EBP           ; restore EBP

The following is a sample assembly language function which implements myrtn.

     Small Memory Model (small code, small data)

     DGROUP        group   _DATA, _BSS

     _TEXT         segment byte public 'CODE'

                   assume  CS:_TEXT

                   assume  DS:DGROUP

                   public  myrtn

     myrtn         proc    near

                   push    EBP

                   ; save EBP

                   mov     EBP,ESP   ; get access to arguments

     ;

     ; body of function

     ;

                   mov     ESP,EBP   ; restore ESP

                   pop     EBP

                   ; restore EBP

                   ret

                   ; return

     myrtn         endp

     _TEXT         ends

     Large Memory Model (big code, big data)

     DGROUP        group             _DATA, _BSS

     MYRTN_TEXT segment byte public 'CODE'

                   assume            CS:MYRTN_TEXT

                   public            myrtn

     myrtn         proc              far

                   push              EBP

                   ; save EBP

                   mov               EBP,ESP

                   ; get access to arguments

     ;

     ; body of function

     ;

                   mov               ESP,EBP

                   ; restore ESP

                   pop               EBP

                   ; restore EBP

                   ret

                   ; return

     myrtn         endp

     MYRTN_TEXT ends

Notes:

1.	Global function names must not be followed with an underscore as was the case with the register-based calling convention.  Global variable names must not be preceded with an underscore as was the case with the register-based calling convention.

2.	All used 80x86 registers except registers EAX, ECX and EDX must be saved on entry and restored on exit.  Segment registers DS and ES must also be saved on entry and restored on exit.  Segment register ES does not have to be saved and restored when using a memory model that is not a small data model.  Note that segment registers only have to be saved and restored if you are compiling your application with the "r" option.

3.	The direction flag must be clear before returning to the caller.

4.	In a small code model, any segment containing executable code must belong to the segment "_TEXT" and the class "CODE".  The segment "_TEXT" must have a "combine" type of "PUBLIC".  On entry, CS contains the segment address of the segment "_TEXT".  In a big code model there is no restriction on the naming of segments which contain executable code.

5.	In a small data model, segment register DS contains the segment address of the group "DGROUP".  This is not the case in a big data model.

6.	When writing assembly language functions for the small code model, you must declare them as "near".  If you wish to write assembly language functions for the big code model, you must declare them as "far".

7.	In general, when naming segments for your code or data, you should follow the conventions described in the section entitled "Memory Layout" in this chapter.

8.	The caller is responsible for removing arguments from the stack.


32-bit:  Functions with Variable Number of Arguments

A function prototype with a parameter list that ends with ",..." has a variable number of arguments.  In this case, all arguments are passed on the stack.  Since no prototyping information exists for arguments represented by ",...", those arguments are passed as described in the section "Passing Arguments".


32-bit:  Returning Values from Functions

The way in which function values are returned depends on the size of the return value.  The following examples describe how function values are to be returned.  They are coded for a small code model.

1.	1-byte values are to be returned in register AL.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret1_

     Ret1_   proc    near   ; char Ret1()

             mov     AL,'G'

             ret

     Ret1_   endp

     _TEXT   ends

             end

2.	2-byte values are to be returned in register AX.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret2_

     Ret2_   proc    near   ; short int Ret2()

             mov     AX,77

             ret

     Ret2_   endp

     _TEXT   ends

             end

3.	4-byte values are to be returned in register EAX.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret4_

     Ret4_   proc    near   ; int Ret4()

             mov     EAX,7777777

             ret

     Ret4_   endp

     _TEXT   ends

             end

4.	8-byte values, except structures, are to be returned in registers EDX and EAX.  When using the "fpc" (floating-point calls) option, "float" and "double" are returned in registers.  See section "Returning Values in 80x87-based Applications" when using the "fpi" or "fpi87" options.

Example:

             .8087

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  Ret8_

     Ret8_   proc    near   ; double Ret8()

             mov     EDX,dword ptr CS:Val8+4

             mov     EAX,dword ptr CS:Val8

             ret

     Val8:   dq      7.7

     Ret8_   endp

     _TEXT   ends

             end

The ".8087" pseudo-op must be specified so that all floating-point constants are generated in 8087 format.

5.	Otherwise, the caller allocates space on the stack for the return value and sets register ESI to point to this area.  In a big data model, register ESI contains an offset relative to the segment value in segment register SS.

Example:

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  RetX_

     ;

     ; struct int_values {

     ;     int value1, value2, value3, value4, value5;

     ;                   };

     ;

     RetX_   proc    near ; struct int_values RetX()

             mov     dword ptr SS:0[ESI],71

             mov     dword ptr SS:4[ESI],72

             mov     dword ptr SS:8[ESI],73

             mov     dword ptr SS:12[ESI],74

             mov     dword ptr SS:16[ESI],75

             ret

     RetX_   endp

     _TEXT   ends

             end

When returning values on the stack, remember to use a segment override to the stack segment (SS).

The following is an example of a Open Watcom C/C++ program calling the above assembly language subprograms.

     #include <stdio.h>

     struct int_values {

         int value1;

         int value2;

         int value3;

         int value4;

         int value5;

     };

     extern  char              Ret1(void);

     extern  short int         Ret2(void);

     extern  long int          Ret4(void);

     extern  double            Ret8(void);

     extern  struct int_values RetX(void);

     void main()

     {

         struct int_values x;

         printf( "Ret1 = %c\n", Ret1() );

         printf( "Ret2 = %d\n", Ret2() );

         printf( "Ret4 = %ld\n", Ret4() );

         printf( "Ret8 = %f\n", Ret8() );

         x = RetX();

         printf( "RetX1 = %d\n", x.value1 );

         printf( "RetX2 = %d\n", x.value2 );

         printf( "RetX3 = %d\n", x.value3 );

         printf( "RetX4 = %d\n", x.value4 );

         printf( "RetX5 = %d\n", x.value5 );

     }

The above function should be compiled for a small code model (use the "mf", "ms" or "mc" compiler option).

  Note:  Returning values from functions in the stack-based calling convention is the same as returning values from functions in the register-based calling convention when using the "fpc" option.


32-bit:  Calling Conventions for 80x87-based Applications

When a source file is compiled by Open Watcom C/C++ with one of the "fpi" or "fpi87" options, all floating-point arguments are passed on the 80x86 stack.  The rules for passing arguments are as follows.

1.	If the argument is not floating-point, use the procedure described earlier in this chapter.

2.	If the argument is floating-point, it is assigned a position on the 80x86 stack.

  Note:  When compiling using the "fpi" or "fpi87" options, the method used for passing floating-point arguments in the stack-based calling convention is identical to the method used in the register-based calling convention.  However, when compiling using the "fpi" or "fpi87" options, the method used for returning floating-point values in the stack-based calling convention is different from the method used in the register-based calling convention.  The register-based calling convention returns floating-point values in ST(0), whereas the stack-based calling convention returns floating-point values in EDX and EAX.


32-bit:  Passing Values in 80x87-based Applications

Consider the following example.

Example:

     extern  void    myrtn(int,float,double,long int);

     void main()

     {

         float    x;

         double   y;

         int      i;

         long int j;

         x = 7.7;

         i = 7;

         y = 77.77

         j = 77;

         myrtn( i, x, y, j );

     }

myrtn is an assembly language function that requires four arguments.  The first argument is of type "int" ( 4 bytes), the second argument is of type "float" (4 bytes), the third argument is of type "double" (8 bytes) and the fourth argument is of type "long int" (4 bytes).

When using the stack-based calling conventions, all of the arguments will be passed on the stack.  When using the register-based calling conventions, the above arguments will be passed to myrtn in the following way:

1.	The first argument will be passed in register EAX leaving EBX, ECX and EDX as available registers for other arguments.

2.	The second argument will be passed on the 80x86 stack since it is a floating-point argument.

3.	The third argument will also be passed on the 80x86 stack since it is a floating-point argument.

4.	The fourth argument will be passed on the 80x86 stack since a previous argument has been assigned a position on the 80x86 stack.

Remember, arguments are pushed on the stack from right to left.  That is, the rightmost argument is pushed first.

Any assembly language function must obey the following rule.

1.	All arguments passed on the stack must be removed by the called function.

The following is a sample assembly language function which implements myrtn.

Example:

             .8087

     _TEXT   segment byte public 'CODE'

             assume  CS:_TEXT

             public  myrtn_

     myrtn_  proc    near

     ;

     ; body of function

     ;

             ret 16           ; return and pop arguments

     myrtn_  endp

     _TEXT   ends

             end

Notes:

1.	Function names must be followed by an underscore.

2.	All used 80x86 registers must be saved on entry and restored on exit except those used to pass arguments and return values, and EAX, which is considered a stratch register.  Note that segment registers only have to saved and restored if you are compiling your application with the "r" option.  In this example, EAX does not have to be saved as it was used to pass the first argument.  Floating-point registers can be modified without saving their contents.

3.	The direction flag must be clear before returning to the caller.

4.	This function has been written for a small code model.  Any segment containing executable code must belong to the class "CODE" and the segment "_TEXT".  On entry, CS contains the segment address of the segment "_TEXT".  The above restrictions do not apply in a big code memory model.

5.	When writing assembly language functions for a small code model, you must declare them as "near".  If you wish to write assembly language functions for a big code model, you must declare them as "far".


32-bit:  Returning Values in 80x87-based Applications

When using the stack-based calling conventions with "fpi" or "fpi87", floating-point values are returned in registers.  Single precision values are returned in EAX, and double precision values are returned in EDX:EAX.

When using the register-based calling conventions with "fpi" or "fpi87", floating-point values are returned in ST(0).  All other values are returned in the manner described earlier in this chapter.


32-bit Pragmas

A pragma is a compiler directive that provides the following capabilities.

•	Pragmas allow you to specify certain compiler options.

•	Pragmas can be used to direct the Open Watcom C/C++ code generator to emit specialized sequences of code for calling functions which use argument passing and value return techniques that differ from the default used by Open Watcom C/C++.

•	Pragmas can be used to describe attributes of functions (such as side effects) that are not possible at the C/C++ language level.  The code generator can use this information to generate more efficient code.

•	Any sequence of in-line machine language instructions, including DOS and BIOS function calls, can be generated in the object code.

Pragmas are specified in the source file using the pragma directive.  The following notation is used to describe the syntax of pragmas.

keywords

A keyword is shown in a mono-spaced courier font.

program-item

A program-item is shown in a roman bold-italics font.  A program-item is a symbol name or numeric value supplied by the programmer.

punctuation

A punctuation character shown in a mono-spaced courier font must be entered as is.

A punctuation character shown in a roman bold-italics font is used to describe syntax.  The following syntactical notation is used.

[abc]

The item abc is optional.

{abc}

The item abc may be repeated zero or more times.

a|b|c

One of a, b or c may be specified.

a ::= b

The item a is defined in terms of b.

(a)

Item a is evaluated first.

The following classes of pragmas are supported.

•	pragmas that specify options

•	pragmas that specify default libraries

•	pragmas that describe the way structures are stored in memory

•	pragmas that provide auxiliary information used for code generation


32-bit:  Using Pragmas to Specify Options

Currently, the following options can be specified with pragmas:

unreferenced

The "unreferenced" option controls the way Open Watcom C/C++ handles unused symbols.  For example,

     #pragma on (unreferenced);

will cause Open Watcom C/C++ to issue warning messages for all unused symbols.  This is the default.  Specifying

     #pragma off (unreferenced);

will cause Open Watcom C/C++ to ignore unused symbols.  Note that if the warning level is not high enough, warning messages for unused symbols will not be issued even if "unreferenced" was specified.

check_stack

The "check_stack" option controls the way stack overflows are to be handled.  For example,

     #pragma on (check_stack);

will cause stack overflows to be detected and

     #pragma off (check_stack);

will cause stack overflows to be ignored.  When "check_stack" is on, Open Watcom C/C++ will generate a run-time call to a stack-checking routine at the start of every routine compiled.  This run-time routine will issue an error if a stack overflow occurs when invoking the routine.  The default is to check for stack overflows.  Stack overflow checking is particularly useful when functions are invoked recursively.  Note that if the stack overflows and stack checking has been suppressed, unpredictable results can occur.

If a stack overflow does occur during execution and you are sure that your program is not in error (i.e.  it is not unnecessarily recursing), you must increase the stack size.  This is done by linking your application again and specifying the "STACK" option to the Open Watcom Linker with a larger stack size.

It is also possible to specify more than one option in a pragma as illustrated by the following example.

     #pragma on (check_stack unreferenced);

reuse_duplicate_strings (C only)

(C Only) The "reuse_duplicate_strings" option controls the way Open Watcom C handles identical strings in an expression.  For example,

     #pragma on (reuse_duplicate_strings);

will cause Open Watcom C to reuse identical strings in an expression.  This is the default.  Specifying

     #pragma off (reuse_duplicate_strings);

will cause Open Watcom C to generate additional copies of the identical string.  The following example shows where this may be of importance to the way the application behaves.

Example:

     #include <stdio.h>

     #pragma off (reuse_duplicate_strings)

     void poke( char *, char * );

     void main()

       {

         poke( "Hello world\n", "Hello world\n" );

       }

     void poke( char *x, char *y )

       {

         x[3] = 'X';

         printf( x );

         y[4] = 'Y';

         printf( y );

       }

     /*

     Default output:

     HelXo world

     HelXY world

     */


32-bit:  Using Pragmas to Specify Default Libraries

Default libraries are specified in special object module records.  Library names are extracted from these special records by the Open Watcom Linker.  When unresolved references remain after processing all object modules specified in linker "FILE" directives, these default libraries are searched after all libraries specified in linker "LIBRARY" directives have been searched.

By default, that is if no library pragma is specified, the Open Watcom C/C++ compiler generates, in the object file defining the main program, default libraries corresponding to the memory model and floating-point model used to compile the file.  For example, if you have compiled the source file containing the main program for the flat memory model and the floating-point calls floating-point model, the libraries "clib3r" and "math3r" will be placed in the object file.

If you wish to add your own default libraries to this list, you can do so with a library pragma.  Consider the following example.

     #pragma library (mylib);

The name "mylib" will be added to the list of default libraries specified in the object file.

If the library specification contains characters such as '\', ':' or ',' (i.e., any character not allowed in a C identifier), you must enclose it in double quotes as in the following example.

     #pragma library ("\watcom\lib286\dos\graph.lib");

     #pragma library ("\watcom\lib386\dos\graph.lib");

If you wish to specify more than one library in a library pragma you must separate them with spaces as in the following example.

     #pragma library (mylib "\watcom\lib286\dos\graph.lib");

     #pragma library (mylib "\watcom\lib386\dos\graph.lib");


32-bit:  The ALIAS Pragma (C Only)

The "alias" pragma can be used to emit alias records in the object file, causing the linker to substitute references to a specified symbol with references to another symbol.  Either identifiers or names (strings) may be used.  Strings are used verbatim, while names corresponding to identifiers are derived as appropriate for the kind and calling convention of the symbol.  The following describes the form of the "alias" pragma.

     #pragma alias ( alias, subst ) [;]

where

description

alias

is either a name or an identifier of the symbol to be aliased.

subst

is either a name or an identifier of the symbol that references to alias will be replaced with.

Consider the following example.

     extern int var;

     void fn( void )

     {

         var = 3;

     }

     #pragma alias ( var, "other_var" );

Instead of var the linker will reference symbol named "other_var".  Symbol var need not be defined, although "other_var" has to be.


32-bit:  The ALLOC_TEXT Pragma (C Only)

The "alloc_text" pragma can be used to specify the name of the text segment into which the generated code for a function, or a list of functions, is to be placed.  The following describes the form of the "alloc_text" pragma.

     #pragma alloc_text ( seg_name, fn {, fn} ) [;]

where

description

seg_name

is the name of the text segment.

fn

is the name of a function.

Consider the following example.

     extern int fn1(int);

     extern int fn2(void);

     #pragma alloc_text ( my_text, fn1, fn2 );

The code for the functions fn1 and fn2 will be placed in the segment my_text.  Note:  function prototypes for the named functions must exist prior to the "alloc_text" pragma.


32-bit:  The CODE_SEG Pragma

The "code_seg" pragma can be used to specify the name of the text segment into which the generated code for functions is to be placed.  The following describes the form of the "code_seg" pragma.

     #pragma code_seg ( seg_name [, class_name] ) [;]

where

description

seg_name

is the name of the text segment optionally enclosed in quotes.  Also, seg_name may be a macro as in:

     #define seg_name "MY_CODE_SEG"

     #pragma code_seg ( seg_name );

class_name

is the optional class name of the text segment and may be enclosed in quotes.  Please note that in order to be recognized by the linker as code, a class name has to end in "CODE".  Also, class_name may be a macro as in:

     #define class_name "MY_CODE"

     #pragma code_seg ( "MY_CODE_SEG", class_name );

Consider the following example.

     #pragma code_seg ( my_text );

     int incr( int i )

     {

         return( i + 1 );

     }

     int decr( int i )

     {

         return( i - 1 );

     }

The code for the functions incr and decr will be placed in the segment my_text.

To return to the default segment, do not specify any string between the opening and closing parenthesis.

     #pragma code_seg ();


32-bit:  The COMMENT Pragma

The "comment" pragma can be used to place a comment record in an object file or executable file.  The following describes the form of the "comment" pragma.

     #pragma comment ( comment_type [, "comment_string"] ) [;]

where

description

comment_type

specifies the type of comment record.  The allowable comment types are:

lib

Default libraries are specified in special object module records.  Library names are extracted from these special records by the Open Watcom Linker.  When unresolved references remain after processing all object modules specified in linker "FILE" directives, these default libraries are searched after all libraries specified in linker "LIBRARY" directives have been searched.

The "lib" form of this pragma offers the same features as the "library" pragma.  See the section entitled 32-bit:  Using Pragmas to Specify Default Libraries for more information.

"comment_string"

is an optional string literal that provides additional information for some comment types.

Consider the following example.

     #pragma comment ( lib, "mylib" );


32-bit:  The DATA_SEG Pragma

The "data_seg" pragma can be used to specify the name of the segment into which data is to be placed.  The following describes the form of the "data_seg" pragma.

     #pragma data_seg ( seg_name [, class_name] ) [;]

where

description

seg_name

is the name of the data segment and may be enclosed in quotes.  Also, seg_name may be a macro as in:

     #define seg_name "MY_DATA_SEG"

     #pragma data_seg ( seg_name );

class_name

is the optional class name of the data segment and may be enclosed in quotes.  Also, class_name may be a macro as in:

     #define class_name "MY_CLASS"

     #pragma data_seg ( "MY_DATA_SEG", class_name );

Consider the following example.

     #pragma data_seg ( my_data );

     static int i;

     static int j;

The data for i and j will be placed in the segment my_data.

To return to the default segment, do not specify any string between the opening and closing parenthesis.

     #pragma data_seg ();


32-bit:  The DISABLE_MESSAGE Pragma

The "disable_message" pragma disables the issuance of specified diagnostic messages.  The form of the "disable_message" pragma is as follows.

     #pragma disable_message ( msg_num {, msg_num} ) [;]

where

description

msg_num

is the number of the diagnostic message.  This number corresponds to the number issued by the compiler.  Make sure to strip all leading zeroes from the message number (to avoid interpretation as an octal constant).

See also the description of 32-bit:  The ENABLE_MESSAGE Pragma.


32-bit:  The DUMP_OBJECT_MODEL Pragma (C++ Only)

The "dump_object_model" pragma causes the C++ compiler to print information about the object model for an indicated class or an enumeration name to the diagnostics file.  For class names, this information includes the offsets and sizes of fields within the class and within base classes.  For enumeration names, this information consists of a list of all the enumeration constants with their values.

The general form of the "dump_object_model" pragma is as follows.

     #pragma dump_object_model class [;]

     #pragma dump_object_model enumeration [;]

     class ::= a defined C++ class free of errors

     enumeration ::= a defined C++ enumeration name

This pragma is designed to be used for information purposes only.


32-bit:  The ENABLE_MESSAGE Pragma

The "enable_message" pragma re-enables the issuance of specified diagnostic messages that have been previously disabled.  The form of the "enable_message" pragma is as follows.

     #pragma enable_message ( msg_num {, msg_num} ) [;]

where

description

msg_num

is the number of the diagnostic message.  This number corresponds to the number issued by the compiler.  Make sure to strip all leading zeroes from the message number (to avoid interpretation as an octal constant).

See also the description of 32-bit:  The DISABLE_MESSAGE Pragma.


32-bit:  The ENUM Pragma

The "enum" pragma affects the underlying storage-definition for subsequent enum declarations.  The forms of the "enum" pragma are as follows.

     #pragma enum int [;]

     #pragma enum minimum [;]

     #pragma enum original [;]

     #pragma enum pop [;]

where

description

int

Make int the underlying storage definition (same as the "ei" compiler option).

minimum

Minimize the underlying storage definition (same as not specifying the "ei" compiler option).

original

Reset back to the original compiler option setting (i.e., what was or was not specified on the command line).

pop

Restore the previous setting.

The first three forms all push the previous setting before establishing the new setting.


32-bit:  The ERROR Pragma

The "error" pragma can be used to issue an error message with the specified text.  The following describes the form of the "error" pragma.

     #pragma error "error text" [;]

where

description

"error text"

is the text of the message that you wish to display.

You should use the ISO #error directive rather than this pragma.  This pragma is provided for compatibility with legacy code.  The following is an example.

     #if defined(__386__)

         ...

     #elseif defined(__86__)

         ...

     #else

     #pragma error ( "neither __386__ or __86__ defined" );

     #endif


32-bit:  The EXTREF Pragma

The "extref" pragma is used to generate a reference to an external function or data item.  The form of the "extref" pragma is as follows.

     #pragma extref name [;]

where

description

name

is the name of an external function or data item.  It must be declared to be an external function or data item before the pragma is encountered.  In C++, when name is a function, it must not be overloaded.

This pragma causes an external reference for the function or data item to be emitted into the object file even if that function or data item is not referenced in the module.  The external reference will cause the linker to include the module containing that name in the linked program or DLL.

This is useful for debugging since you can cause debugging routines (callable from within debugger) to be included into a program or DLL to be debugged.

In C++, you can also force constructors and/or destructors to be called for a data item without necessarily referencing the data item anywhere in your code.


32-bit:  The FUNCTION Pragma

Certain functions, such as those listed in the description of the "oi" and "om" options, have intrinsic forms.  These functions are special functions that are recognized by the compiler and processed in a special way.  For example, the compiler may choose to generate in-line code for the function.  The intrinsic attribute for these special functions is set by specifying the "oi" or "om" option or using an "intrinsic" pragma.  The "function" pragma can be used to remove the intrinsic attribute for a specified list of functions.

The following describes the form of the "function" pragma.

     #pragma function ( fn {, fn} ) [;]

where

description

fn

is the name of a function.

Suppose the following source code was compiled using the "om" option so that when one of the special math functions is referenced, the intrinsic form will be used.  In our example, we have referenced the function sin which does have an intrinsic form.  By specifying sin in a "function" pragma, the intrinsic attribute will be removed, causing the function sin to be treated as a regular user-defined function.

     #include <math.h>

     #pragma function( sin );

     double test( double x )

     {

         return( sin( x ) );

     }


32-bit:  The INCLUDE_ALIAS Pragma

In certain situations, it can be advantageous to remap the names of include files.  Most commonly this occurs on systems that do not support long file names when building source code that references header files with long names.

The form of the "include_alias" pragma follows.

     #pragma include_alias ( "alias_name", "real_name" ) [;]

     #pragma include_alias ( <alias_name>, <real_name> ) [;]

where

description

alias_name

is the name referenced in include directives in source code.

real_name

is the translated name that the compiler will reference instead.

The following is an example.

     #pragma include_alias( "LongFileName.h", "lfn.h" )

     #include "LongFileName.h"

In the example, the compiler will attempt to read lfn.h when LongFileName.h was included.

Note that only simple textual substitution is performed.  The aliased name must match exactly, including double quotes or angle brackets, as well as any directory separators.  Also, double quotes and angle brackets may not be mixed a single pragma.

The value of the predefined __FILE__ symbol, as well as the filename reported in error messages, will be the true filename after substitution was performed.


32-bit:  Setting Priority of Static Data Initialization (C++ Only)

The "initialize" pragma sets the priority for initialization of static data in the file.  This priority only applies to initialization of static data that requires the execution of code.  For example, the initialization of a class that contains a constructor requires the execution of the constructor.  Note that if the sequence in which initialization of static data in your program takes place has no dependencies, the "initialize" pragma need not be used.

The general form of the "initialize" pragma is as follows.

     #pragma initialize [before | after] priority [;]

     priority ::= n | library | program

where

description

n

is a number representing the priority and must be in the range 0-255.  The larger the priority, the later the point at which initialization will occur.

Priorities in the range 0-20 are reserved for the C++ compiler.  This is to ensure that proper initialization of the C++ run-time system takes place before the execution of your program.  The "library" keyword represents a priority of 32 and can be used for class libraries that require initialization before the program is initialized.  The "program" keyword represents a priority of 64 and is the default priority for any compiled code.  Specifying "before" adjusts the priority by subtracting one.  Specifying "after" adjusts the priority by adding one.

A source file containing the following "initialize" pragma specifies that the initialization of static data in the file will take place before initialization of all other static data in the program since a priority of 63 will be assigned.

Example:

     #pragma initialize before program

If we specify "after" instead of "before", the initialization of the static data in the file will occur after initialization of all other static data in the program since a priority of 65 will be assigned.

Note that the following is equivalent to the "before" example

Example:

     #pragma initialize 63

and the following is equivalent to the "after" example.

Example:

     #pragma initialize 65

The use of the "before", "after", and "program" keywords are more descriptive in the intent of the pragmas.

It is recommended that a priority of 32 (the priority used when the "library" keyword is specified) be used when developing class libraries.  This will ensure that initialization of static data defined by the class library will take place before initialization of static data defined by the program.  The following "initialize" pragma can be used to achieve this.

Example:

     #pragma initialize library


32-bit:  The INLINE_DEPTH Pragma (C++ Only)

When an in-line function is called, the function call may be replaced by the in-line expansion for that function.  This in-line expansion may include calls to other in-line functions which can also be expanded.  The "inline_depth" pragma can be used to set the number of times this expansion of in-line functions will occur for a call.

The form of the "inline_depth" pragma is as follows.

     #pragma inline_depth [(] n [)] [;]

where

description

n

is the depth of expansion.  If n is 0, no expansion will occur.  If n is 1, only the original call is expanded.  If n is 2, the original call and the in-line functions invoked by the original function will be expanded.  The default value for n is 3.  The maximum value for n is 255.  Note that no expansion of recursive in-line functions occur unless enabled using the "inline_recursion" pragma.


32-bit:  The INLINE_RECURSION Pragma (C++ Only)

The "inline_recursion" pragma controls the recursive expansion of inline functions.  The form of the "inline_recursion" pragma is as follows.

     #pragma inline_recursion [(] on | off [)] [;]

Specifying "on" will enable expansion of recursive inline functions.  The depth of expansion is specified by the "inline_depth" pragma.  The default depth is 3.  Specifying "off" suppresses expansion of recursive inline functions.  This is the default.


32-bit:  The INTRINSIC Pragma

Certain functions, those listed in the description of the "oi" option, have intrinsic forms.  These functions are special functions that are recognized by the compiler and processed in a special way.  For example, the compiler may choose to generate in-line code for the function.  The intrinsic attribute for these special functions is set by specifying the "oi" option or using an "intrinsic" pragma.

The following describes the form of the "intrinsic" pragma.

     #pragma intrinsic ( fn {, fn} ) [;]

where

description

fn

is the name of a function.

Suppose the following source code was compiled without using the "oi" option so that no function had the intrinsic attribute.  If we wanted the intrinsic form of the sin function to be used, we could specify the function in an "intrinsic" pragma.

     #include <math.h>

     #pragma intrinsic( sin );

     double test( double x )

     {

         return( sin( x ) );

     }


32-bit:  The MESSAGE Pragma

The "message" pragma can be used to issue a message with the specified text to the standard output without terminating compilation.  The following describes the form of the "message" pragma.

     #pragma message ( "message text" ) [;]

where

description

"message text"

is the text of the message that you wish to display.

The following is an example.

     #if defined(__386__)

         ...

     #else

     #pragma message ( "assuming 16-bit compile" );

     #endif


32-bit:  The ONCE Pragma

The "once" pragma can be used to indicate that the file which contains this pragma should only be opened and processed "once".  The following describes the form of the "once" pragma.

     #pragma once [;]

Assume that the file "foo.h" contains the following text.

Example:

     #ifndef _FOO_H_INCLUDED

     #define _FOO_H_INCLUDED

     #pragma once

         .

         .

         .

     #endif

The first time that the compiler processes "foo.h" and encounters the "once" pragma, it records the file's name.  Subsequently, whenever the compiler encounters a #include statement that refers to "foo.h", it will not open the include file again.  This can help speed up processing of #include files and reduce the time required to compile an application.


32-bit:  The PACK Pragma

The "pack" pragma can be used to control the way in which structures are stored in memory.  There are 4 forms of the "pack" pragma.

The following form of the "pack" pragma can be used to change the alignment of structures and their fields in memory.

     #pragma pack ( n ) [;]

where

description

n

is 1, 2, 4, 8 or 16 and specifies the method of alignment.

The alignment of structure members is described in the following table.  If the size of the member is 1, 2, 4, 8 or 16, the alignment is given for each of the "zp" options.  If the member of the structure is an array or structure, the alignment is described by the row "x".

                         zp1     zp2     zp4     zp8     zp16

     sizeof(member)  \---------------------------------------

             1       |   0       0       0       0       0

             2       |   0       2       2       2       2

             4       |   0       2       4       4       4

             8       |   0       2       4       8       8

             16      |   0       2       4       8       16

             x       |   aligned to largest member

An alignment of 0 means no alignment, 2 means word boundary, 4 means doubleword boundary, etc.  If the largest member of structure "x" is 1 byte then "x" is not aligned.  If the largest member of structure "x" is 2 bytes then "x" is aligned according to row 2.  If the largest member of structure "x" is 4 bytes then "x" is aligned according to row 4.  If the largest member of structure "x" is 8 bytes then "x" is aligned according to row 8.  If the largest member of structure "x" is 16 bytes then "x" is aligned according to row 16.

If no value is specified in the "pack" pragma, a default value of 8 is used.  Note that the default value can be changed with the "zp" Open Watcom C/C++ compiler command line option.

The following form of the "pack" pragma can be used to save the current alignment amount on an internal stack.

     #pragma pack ( push ) [;]

The following form of the "pack" pragma can be used to save the current alignment amount on an internal stack and set the current alignment.

     #pragma pack ( push, number ) [;]

The following form of the "pack" pragma can be used to restore the previous alignment amount from an internal stack.

     #pragma pack ( pop ) [;]


32-bit:  The READ_ONLY_FILE Pragma

Explicit listing of dependencies in a makefile can often be tedious in the development and maintenance phases of a project.  The Open Watcom C/C++ compiler will insert dependency information into the object file as it processes source files so that a complete snapshot of the files necessary to build the object file are recorded.  The "read_only_file" pragma can be used to prevent the name of the source file that includes it from being included in the dependency information that is written to the object file.

This pragma is commonly used in system header files since they change infrequently (and, when they do, there should be no impact on source files that have included them).

The form of the "read_only_file" pragma follows.

     #pragma read_only_file [;]

For more information on make dependencies, see the section entitled "Automatic Dependency Detection (.AUTODEPEND)" in the Open Watcom C/C++ Tools User's Guide.


32-bit:  The TEMPLATE_DEPTH Pragma (C++ Only)

The "template_depth" pragma provides a hard limit for the amount of nested template expansions allowed so that infinite expansion can be detected.

The form of the "template_depth" pragma is as follows.

     #pragma template_depth [(] n [)] [;]

where

description

n

is the depth of expansion.  If the value of n is less than 2, if will default to 2.  If n is not specified, a warning message will be issued and the default value for n will be 100.

The following example of recursive template expansion illustrates why this pragma can be useful.

Example:

     #pragma template_depth(10);

     template <class T>

     struct S {

         S<T*> x;

     };

     S<char> v;


32-bit:  The WARNING Pragma (C++ Only)

The "warning" pragma sets the level of warning messages.  The form of the "warning" pragma is as follows.

     #pragma warning msg_num level [;]

where

description

msg_num

is the number of the warning message.  This number corresponds to the number issued by the compiler.  If msg_num is "*", the level of all warning messages is changed to the specified level.  Make sure to strip all leading zeroes from the message number (to avoid interpretation as an octal constant).

level

is a number from 0 to 9 and represents the level of the warning message.  When a value of zero is specified, the warning becomes an error.


32-bit:  Auxiliary Pragmas

The following sections describe the capabilities provided by auxiliary pragmas.


32-bit:  Specifying Symbol Attributes

Auxiliary pragmas are used to describe attributes that affect code generation.  Initially, the compiler defines a default set of attributes.  Each auxiliary pragma refers to one of the following.

1.	a symbol (such as a variable or function)

2.	a type definition that resolves to a function type

3.	the default set of attributes defined by the compiler

When an auxiliary pragma refers to a particular symbol, a copy of the current set of default attributes is made and merged with the attributes specified in the auxiliary pragma.  The resulting attributes are assigned to the specified symbol and can only be changed by another auxiliary pragma that refers to the same symbol.

An example of a type definition that resolves to a function type is the following.

     typedef void (*func_type)();

When an auxiliary pragma refers to a such a type definition, a copy of the current set of default attributes is made and merged with the attributes specified in the auxiliary pragma.  The resulting attributes are assigned to each function whose type matches the specified type definition.

When "default" is specified instead of a symbol name, the attributes specified by the auxiliary pragma change the default set of attributes.  The resulting attributes are used by all symbols that have not been specifically referenced by a previous auxiliary pragma.

Note that all auxiliary pragmas are processed before code generation begins.  Consider the following example.

     code in which symbol x is referenced

     #pragma aux y <attrs_1>;

     code in which symbol y is referenced

     code in which symbol z is referenced

     #pragma aux default <attrs_2>;

     #pragma aux x <attrs_3>;

Auxiliary attributes are assigned to x, y and z in the following way.

1.	Symbol x is assigned the initial default attributes merged with the attributes specified by <attrs_2> and <attrs_3>.

2.	Symbol y is assigned the initial default attributes merged with the attributes specified by <attrs_1>.

3.	Symbol z is assigned the initial default attributes merged with the attributes specified by <attrs_2>.


32-bit:  Alias Names

When a symbol referred to by an auxiliary pragma includes an alias name, the attributes of the alias name are also assumed by the specified symbol.

There are two methods of specifying alias information.  In the first method, the symbol assumes only the attributes of the alias name; no additional attributes can be specified.  The second method is more general since it is possible to specify an alias name as well as additional auxiliary information.  In this case, the symbol assumes the attributes of the alias name as well as the attributes specified by the additional auxiliary information.

The simple form of the auxiliary pragma used to specify an alias is as follows.

     #pragma aux ( sym, [far16] alias ) [;]

where

description

sym

is any valid C/C++ identifier.

alias

is the alias name and is any valid C/C++ identifier.

The far16 attribute should only be used on systems that permit the calling of 16-bit code from 32-bit code.  Currently, the only supported operating system that allows this is 32-bit OS/2.  If you have any libraries of functions or APIs that are only available as 16-bit code and you wish to access these functions and APIs from 32-bit code, you must specify the far16 attribute.  If the far16 attribute is specified, the compiler will generate special code which allows the 16-bit code to be called from 32-bit code.  Note that a far16 function must be a function whose attributes are those specified by one of the alias names __cdecl or __pascal .  These alias names will be described in a later section.

Consider the following example.

     #pragma aux push_args parm [] ;

     #pragma aux ( rtn, push_args ) ;

The routine rtn assumes the attributes of the alias name push_args which specifies that the arguments to rtn are passed on the stack.

Let us look at an example in which the symbol is a type definition.

     typedef void (func_type)(int);

     #pragma aux push_args parm [];

     #pragma aux ( func_type, push_args );

     extern func_type rtn1;

     extern func_type rtn2;

The first auxiliary pragma defines an alias name called push_args that specifies the mechanism to be used to pass arguments.  The mechanism is to pass all arguments on the stack.  The second auxiliary pragma associates the attributes specified in the first pragma with the type definition func_type.  Since rtn1 and rtn2 are of type func_type, arguments to either of those functions will be passed on the stack.

The general form of an auxiliary pragma that can be used to specify an alias is as follows.

     #pragma aux ( alias ) sym aux_attrs [;]

where

description

alias

is the alias name and is any valid C/C++ identifier.

sym

is any valid C/C++ identifier.

aux_attrs

are attributes that can be specified with the auxiliary pragma.

Consider the following example.

     #pragma aux HIGH_C "*"                                 \

                        parm caller []                      \

                        value no8087                        \

                        modify [eax ecx edx fs gs];

     #pragma aux (HIGH_C) rtn1;

     #pragma aux (HIGH_C) rtn2;

     #pragma aux (HIGH_C) rtn3;

The routines rtn1, rtn2 and rtn3 assume the same attributes as the alias name HIGH_C which defines the calling convention used by the MetaWare High C compiler.  Note that register ES must also be specified in the "modify" register set when using a memory model that is not a small data model.  Whenever calls are made to rtn1, rtn2 and rtn3, the MetaWare High C calling convention will be used.

Note that if the attributes of HIGH_C change, only one pragma needs to be changed.  If we had not used an alias name and specified the attributes in each of the three pragmas for rtn1, rtn2 and rtn3, we would have to change all three pragmas.  This approach also reduces the amount of memory required by the compiler to process the source file.

  WARNING!  The alias name HIGH_C is just another symbol.  If HIGH_C appeared in your source code, it would assume the attributes specified in the pragma for HIGH_C.


32-bit:  Predefined Aliases

A number of symbols are predefined by the compiler with a set of attributes that describe a particular calling convention.  These symbols can be used as aliases.  The following is a list of these symbols.

__cdecl

 __cdecl or  cdecl defines the calling convention used by Microsoft compilers.

__fastcall

 __fastcall or  fastcall defines the calling convention used by Microsoft compilers.

__fortran

 __fortran or  fortran defines the calling convention used by Open Watcom FORTRAN compilers.

__pascal

 __pascal or  pascal defines the calling convention used by OS/2 1.x and Windows 3.x API functions.

__stdcall

 __stdcall or  stdcall defines a special calling convention used by the Win32 API functions.

__syscall

 __syscall or  syscall defines the calling convention used by the 32-bit OS/2 API functions.

__system

 __system or  system are identical to __syscall .

__watcall

 __watcall or  watcall defines the calling convention used by Open Watcom compilers.

The following describes the attributes of the above alias names.


32-bit:  Predefined "__cdecl" Alias

     #pragma aux __cdecl "_*" \

                parm caller [] \

                value struct float struct routine [eax] \

                modify [eax ecx edx]

Notes:

1.	All symbols are preceded by an underscore character.

2.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The calling routine will remove the arguments from the stack.

3.	Floating-point values are returned in the same way as structures.  When a structure is returned, the called routine allocates space for the return value and returns a pointer to the return value in register EAX.

4.	Registers EAX, ECX and EDX are not saved and restored when a call is made.


32-bit:  Predefined "__pascal" Alias

     #pragma aux __pascal "^" \

                parm reverse routine [] \

                value struct float struct caller [] \

                modify [eax ebx ecx edx]

Notes:

1.	All symbols are mapped to upper case.

2.	Arguments are pushed on the stack in reverse order.  That is, the first argument is pushed first, the second argument is pushed next, and so on.  The routine being called will remove the arguments from the stack.

3.	Floating-point values are returned in the same way as structures.  When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.

4.	Registers EAX, EBX, ECX and EDX are not saved and restored when a call is made.


32-bit:  Predefined "__stdcall" Alias

     #pragma aux __stdcall "_*@nnn" \

                parm routine [] \

                value struct struct caller [] \

                modify [eax ecx edx]

Notes:

1.	All symbols are preceded by an underscore character.

2.	All C symbols (extern "C" symbols in C++) are suffixed by "@nnn" where "nnn" is the sum of the argument sizes (each size is rounded up to a multiple of 4 bytes so that char and short are size 4).  When the argument list contains "...", the "@nnn" suffix is omitted.

3.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The called routine will remove the arguments from the stack.

4.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.  Floating-point values are returned in 80x87 register ST(0).

5.	Registers EAX, ECX and EDX are not saved and restored when a call is made.


32-bit:  Predefined "__syscall" Alias

     #pragma aux __syscall "*" \

                parm caller [] \

                value struct struct caller [] \

                modify [eax ecx edx]

Notes:

1.	Symbols names are not modified, that is, they are not adorned with leading or trailing underscores.

2.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The calling routine will remove the arguments from the stack.

3.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.  Floating-point values are returned in 80x87 register ST(0).

4.	Registers EAX, ECX and EDX are not saved and restored when a call is made.


32-bit:  Predefined "__watcall" Alias (register calling convention)

     #pragma aux __watcall "*_" \

                parm routine [eax ebx ecx edx] \

                value struct caller

Notes:

1.	Symbol names are followed by an underscore character.

2.	Arguments are processed from left to right.  The leftmost arguments are passed in registers and the rightmost arguments are passed on the stack (if the registers used for argument passing have been exhausted).  Arguments that are passed on the stack are pushed from right to left.  The calling routine will remove the arguments if any were pushed on the stack.

3.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space is put into ESI register.  The called routine then places the return value there.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.

4.	Floating-point values are returned using 80x86 registers ("fpc" option) or using 80x87 floating-point registers ("fpi" or "fpi87" option).

5.	All registers must be preserved by the called routine.


32-bit:  Predefined "__watcall" Alias (stack calling convention)

     #pragma aux __watcall "*" \

                parm caller [] \

                value no8087 struct caller \

                modify [eax ecx edx 8087]

Notes:

1.	All symbols appear in object form as they do in source form.

2.	Arguments are pushed on the stack from right to left.  That is, the last argument is pushed first.  The calling routine will remove the arguments from the stack.

3.	When a structure is returned, the caller allocates space on the stack.  The address of the allocated space will be pushed on the stack immediately before the call instruction.  Upon returning from the call, register EAX will contain address of the space allocated for the return value.

4.	Floating-point values are returned only using 80x86 registers.

5.	Registers EAX, ECX and EDX are not preserved by the called routine.

6.	Any local variables that are located in the 80x87 cache are not preserved by the called routine.


32-bit:  Alternate Names for Symbols

The following form of the auxiliary pragma can be used to describe the mapping of a symbol from its source form to its object form.

     #pragma aux sym obj_name [;]

where

description

sym

is any valid C/C++ identifier.

obj_name

is any character string enclosed in double quotes.

When specifying obj_name, some characters have a special meaning:

where

description

*

is unmodified symbol name

^

is symbol name converted to uppercase

!

is symbol name converted to lowercase

#

is a placeholder for "@nnn", where nnn is size of all function parameters on the stack; it is ignored for functions with variable argument lists, or for symbols that are not functions

\

next character is treated as literal

Several examples of source to object form symbol name translation follow:

In the following example, the name "MyRtn" will be replaced by "MyRtn_" in the object file.

     #pragma aux MyRtn "*_";

This is the default for all function names.

In the following example, the name "MyVar" will be replaced by "_MyVar" in the object file.

     #pragma aux MyVar "_*";

This is the default for all variable names.

In the following example, the lower case version "myrtn" will be placed in the object file.

     #pragma aux MyRtn "!";

In the following example, the upper case version "MYRTN" will be placed in the object file.

     #pragma aux MyRtn "^";

In the following example, the name "MyRtn" will be replaced by "_MyRtn@nnn" in the object file.  "nnn" represents the size of all function parameters.

     #pragma aux MyRtn "_*#";

In the following example, the name "MyRtn" will be replaced by "_MyRtn#" in the object file.

     #pragma aux MyRtn "_*\#";

The default mapping for all symbols can also be changed as illustrated by the following example.

     #pragma aux default "_*_";

The above auxiliary pragma specifies that all names will be prefixed and suffixed by an underscore character ('_').


32-bit:  Describing Calling Information

The following form of the auxiliary pragma can be used to describe the way a function is to be called.

     #pragma aux sym far [;]

         or

     #pragma aux sym near [;]

         or

     #pragma aux sym = in_line [;]

     in_line ::= { const | (seg id) | (offset id) | (reloff id)

                         | "asm" }

where

description

sym

is a function name.

const

is a valid C/C++ integer constant.

id

is any valid C/C++ identifier.

seg

specifies the segment of the symbol id.

offset

specifies the offset of the symbol id.

reloff

specifies the relative offset of the symbol id for near control transfers.

asm

is an assembly language instruction or directive.

In the following example, Open Watcom C/C++ will generate a far call to the function myrtn.

     #pragma aux myrtn far;

Note that this overrides the calling sequence that would normally be generated for a particular memory model.  In other words, a far call will be generated even if you are compiling for a memory model with a small code model.

In the following example, Open Watcom C/C++ will generate a near call to the function myrtn.

     #pragma aux myrtn near;

Note that this overrides the calling sequence that would normally be generated for a particular memory model.  In other words, a near call will be generated even if you are compiling for a memory model with a big code model.

In the following DOS example, Open Watcom C/C++ will generate the sequence of bytes following the "=" character in the auxiliary pragma whenever a call to mode4 is encountered.  mode4 is called an in-line function.

     void mode4(void);

     #pragma aux mode4 =                \

         0xb4 0x00       /* mov AH,0 */ \

         0xb0 0x04       /* mov AL,4 */ \

         0xcd 0x10       /* int 10H  */ \

         modify [ AH AL ];

The sequence in the above DOS example represents the following lines of assembly language instructions.

     mov   AH,0       ; select function "set mode"

     mov   AL,4       ; specify mode (mode 4)

     int   10H        ; BIOS video call

The above example demonstrates how to generate BIOS function calls in-line without writing an assembly language function and calling it from your C/C++ program.  The C prototype for the function mode4 is not necessary but is included so that we can take advantage of the argument type checking provided by Open Watcom C/C++.

The following DOS example is equivalent to the above example but mnemonics for the assembly language instructions are used instead of the binary encoding of the assembly language instructions.

     void mode4(void);

     #pragma aux mode4 =     \

         "mov AH,0",         \

         "mov AL,4",         \

         "int 10H"           \

         modify [ AH AL ];

A sequence of in-line assembly language instructions may contain symbolic references.  In the following example, a near call to the function myalias is made whenever myrtn is called.

     extern void myalias(void);

     void myrtn(void);

     #pragma aux myrtn =                     \

         0xe8 reloff myalias /* near call */;

In the following example, a far call to the function myalias is made whenever myrtn is called.

     extern void myalias(void);

     void myrtn(void);

     #pragma aux myrtn =                                \

         0x9a offset myalias seg myalias /* far call */;


32-bit:  Loading Data Segment Register

An application may have been compiled so that the segment register DS does not contain the segment address of the default data segment (group "DGROUP").  This is usually the case if you are using a large data memory model.  Suppose you wish to call a function that assumes that the segment register DS contains the segment address of the default data segment.  It would be very cumbersome if you were forced to compile your application so that the segment register DS contained the default data segment (a small data memory model).

The following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment address of the default data segment before calling the specified function.

     #pragma aux sym parm loadds [;]

where

description

sym

is a function name.

Alternatively, the following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment address of the default data segment as part of the prologue sequence for the specified function.

     #pragma aux sym loadds [;]

where

description

sym

is a function name.


32-bit:  Defining Exported Symbols in Dynamic Link Libraries

An exported symbol in a dynamic link library is a symbol that can be referenced by an application that is linked with that dynamic link library.  Normally, symbols in dynamic link libraries are exported using the Open Watcom Linker "EXPORT" directive.  An alternative method is to use the following form of the auxiliary pragma.

     #pragma aux sym export [;]

where

description

sym

is a function name.


32-bit:  Forcing a Stack Frame

Normally, a function contains a stack frame if arguments are passed on the stack or an automatic variable is allocated on the stack.  No stack frame will be generated if the above conditions are not satisfied.  The following form of the auxiliary pragma will force a stack frame to be generated under any circumstance.

     #pragma aux sym frame [;]

where

description

sym

is a function name.


32-bit:  Describing Argument Information

Using auxiliary pragmas, you can describe the calling convention that Open Watcom C/C++ is to use for calling functions.  This is particularly useful when interfacing to functions that have been compiled by other compilers or functions written in other programming languages.

The general form of an auxiliary pragma that describes argument passing is the following.

     #pragma aux sym parm { pop_info | reverse | {reg_set} } [;]

     pop_info ::= caller | routine

where

description

sym

is a function name.

reg_set

is called a register set.  The register sets specify the registers that are to be used for argument passing.  A register set is a list of registers separated by spaces and enclosed in square brackets.


32-bit:  Passing Arguments in Registers

The following form of the auxiliary pragma can be used to specify the registers that are to be used to pass arguments to a particular function.

     #pragma aux sym parm {reg_set} [;]

where

description

sym

is a function name.

reg_set

is called a register set.  The register sets specify the registers that are to be used for argument passing.  A register set is a list of registers separated by spaces and enclosed in square brackets.

Register sets establish a priority for register allocation during argument list processing.  Register sets are processed from left to right.  However, within a register set, registers are chosen in any order.  Once all register sets have been processed, any remaining arguments are pushed on the stack.

Note that regardless of the register sets specified, only certain combinations of registers will be selected for arguments of a particular type.

Note that arguments of type float and double are always pushed on the stack when the "fpi" or "fpi87" option is used.

double

Arguments of type double can only be passed in one of the following register pairs:  EDX:EAX, ECX:EBX, ECX:EAX, ECX:ESI, EDX:EBX, EDI:EAX, ECX:EDI, EDX:ESI, EDI:EBX, ESI:EAX, ECX:EDX, EDX:EDI, EDI:ESI, ESI:EBX or EBX:EAX.  For example, if the following register set was specified for a routine having an argument of type double,

     [EBP EBX]

the argument would be pushed on the stack since a valid register combination for 8-byte arguments is not contained in the register set.  Note that this method for passing arguments of type double is supported only when the "fpc" option is used.  Note that this argument passing method does not include the passing of 8-byte structures.

far pointer

A far pointer can only be passed in one of the following register pairs:  DX:EAX, CX:EBX, CX:EAX, CX:ESI, DX:EBX, DI:EAX, CX:EDI, DX:ESI, DI:EBX, SI:EAX, CX:EDX, DX:EDI, DI:ESI, SI:EBX, BX:EAX, FS:ECX, FS:EDX, FS:EDI, FS:ESI, FS:EBX, FS:EAX, GS:ECX, GS:EDX, GS:EDI, GS:ESI, GS:EBX, GS:EAX, DS:ECX, DS:EDX, DS:EDI, DS:ESI, DS:EBX, DS:EAX, ES:ECX, ES:EDX, ES:EDI, ES:ESI, ES:EBX or ES:EAX.  For example, if a far pointer is passed to a function with the following register set,

     [ES EBP]

the argument would be pushed on the stack since a valid register combination for a far pointer is not contained in the register set.

int

The only registers that will be assigned to 4-byte arguments (e.g., arguments of type int) are:  EAX, EBX, ECX, EDX, ESI and EDI.  For example, if the following register set was specified for a routine with one argument of type int,

     [EBP]

the argument would be pushed on the stack since a valid register combination for 4-byte arguments is not contained in the register set.  Note that this argument passing method includes 4-byte structures.  Note that this argument passing method also includes arguments of type float but only when the "fpc" option is used.

char, short int

Arguments whose size is 1 byte or 2 bytes (e.g., arguments of type char and short int as well as 2-byte structures) are promoted to 4 bytes and are then assigned registers as if they were 4-byte arguments.

others

Arguments that do not fall into one of the above categories cannot be passed in registers and are pushed on the stack.  Once an argument has been assigned a position on the stack, all remaining arguments will be assigned a position on the stack even if all register sets have not yet been exhausted.

Notes:

1.	The default register set is [EAX EBX ECX EDX].

2.	Specifying registers AH and AL is equivalent to specifying register AX.  Specifying registers DH and DL is equivalent to specifying register DX.  Specifying registers CH and CL is equivalent to specifying register CX.  Specifying registers BH and BL is equivalent to specifying register BX.  Specifying register EAX implies that register AX has been specified.  Specifying register EBX implies that register BX has been specified.  Specifying register ECX implies that register CX has been specified.  Specifying register EDX implies that register DX has been specified.  Specifying register EDI implies that register DI has been specified.  Specifying register ESI implies that register SI has been specified.  Specifying register EBP implies that register BP has been specified.  Specifying register ESP implies that register SP has been specified.

3.	If you are compiling for a memory model with a small data model, or the "zdp" compiler option is specified, any register combination containing register DS becomes illegal.  In a small data model, segment register DS must remain unchanged as it points to the program's data segment.  Note that the "zdf" compiler option can be used to specify that register DS does not contain that segment address of the program's data segment.  In this case, register combinations containing register DS are legal.

4.	If you are compiling for the flat memory model, any register combination containing DS or ES becomes illegal.  In a flat memory model, code and data reside in the same segment.  Segment registers DS and ES point to this segment and must remain unchanged.

Consider the following example.

     #pragma aux myrtn parm [eax ebx ecx edx] [ebp esi];

Suppose myrtn is a routine with 3 arguments each of type double.

1.	The first argument will be passed in the register pair EDX:EAX.

2.	The second argument will be passed in the register pair ECX:EBX.

3.	The third argument will be pushed on the stack since EBP:ESI is not a valid register pair for arguments of type double.

It is possible for registers from the second register set to be used before registers from the first register set are used.  Consider the following example.

     #pragma aux myrtn parm [eax ebx ecx edx] [esi edi];

Suppose myrtn is a routine with 3 arguments, the first of type int and the second and third of type double.

1.	The first argument will be passed in the register EAX.

2.	The second argument will be passed in the register pair ECX:EBX.

3.	The third argument will be passed in the register set EDI:ESI.

Note that registers are no longer selected from a register set after registers are selected from subsequent register sets, even if all registers from the original register set have not been exhausted.

An empty register set is permitted.  All subsequent register sets appearing after an empty register set are ignored; all remaining arguments are pushed on the stack.

Notes:

1.	If a single empty register set is specified, all arguments are passed on the stack.

2.	If no register set is specified, the default register set [EAX EBX ECX EDX] is used.


32-bit:  Forcing Arguments into Specific Registers

It is possible to force arguments into specific registers.  Suppose you have a function, say "mycopy", that copies data.  The first argument is the source, the second argument is the destination, and the third argument is the length to copy.  If we want the first argument to be passed in the register ESI, the second argument to be passed in register EDI and the third argument to be passed in register ECX, the following auxiliary pragma can be used.

     void mycopy( char near *, char *, int );

     #pragma aux mycopy parm [ESI] [EDI] [ECX];

Note that you must be aware of the size of the arguments to ensure that the arguments get passed in the appropriate registers.


32-bit:  Passing Arguments to In-Line Functions

For functions whose code is generated by Open Watcom C/C++ and whose argument list is described by an auxiliary pragma, Open Watcom C/C++ has some freedom in choosing how arguments are assigned to registers.  Since the code for in-line functions is specified by the programmer, the description of the argument list must be very explicit.  To achieve this, Open Watcom C/C++ assumes that each register set corresponds to an argument.  Consider the following DOS example of an in-line function called scrollactivepgup.

     void scrollactivepgup(char,char,char,char,char,char);

     #pragma aux scrollactivepgup = \

         "mov AH,6"   \

         "int 10h"    \

         parm [ch] [cl] [dh] [dl] [al] [bh] \

         modify [ah];

The BIOS video call to scroll the active page up requires the following arguments.

1.	The row and column of the upper left corner of the scroll window is passed in registers CH and CL respectively.

2.	The row and column of the lower right corner of the scroll window is passed in registers DH and DL respectively.

3.	The number of lines blanked at the bottom of the window is passed in register AL.

4.	The attribute to be used on the blank lines is passed in register BH.

When passing arguments, Open Watcom C/C++ will convert the argument so that it fits in the register(s) specified in the register set for that argument.  For example, in the above example, if the first argument to scrollactivepgup was called with an argument whose type was int, it would first be converted to char before assigning it to register CH.  Similarly, if an in-line function required its argument in register EAX and the argument was of type short int, the argument would be converted to long int before assigning it to register EAX.

In general, Open Watcom C/C++ assigns the following types to register sets.

1.	A register set consisting of a single 8-bit register (1 byte) is assigned a type of unsigned char.

2.	A register set consisting of a single 16-bit register (2 bytes) is assigned a type of unsigned short int.

3.	A register set consisting of a single 32-bit register (4 bytes) is assigned a type of unsigned long int.

4.	A register set consisting of two 32-bit registers (8 bytes) is assigned a type of double.


32-bit:  Removing Arguments from the Stack

The following form of the auxiliary pragma specifies who removes from the stack arguments that were pushed on the stack.

     #pragma aux sym parm (caller | routine) [;]

where

description

sym

is a function name.

"caller" specifies that the caller will pop the arguments from the stack; "routine" specifies that the called routine will pop the arguments from the stack.  If "caller" or "routine" is omitted, "routine" is assumed unless the default has been changed in a previous auxiliary pragma, in which case the new default is assumed.


32-bit:  Passing Arguments in Reverse Order

The following form of the auxiliary pragma specifies that arguments are passed in the reverse order.

     #pragma aux sym parm reverse [;]

where

description

sym

is a function name.

Normally, arguments are processed from left to right.  The leftmost arguments are passed in registers and the rightmost arguments are passed on the stack (if the registers used for argument passing have been exhausted).  Arguments that are passed on the stack are pushed from right to left.

When arguments are reversed, the rightmost arguments are passed in registers and the leftmost arguments are passed on the stack (if the registers used for argument passing have been exhausted).  Arguments that are passed on the stack are pushed from left to right.

Reversing arguments is most useful for functions that require arguments to be passed on the stack in an order opposite from the default.  The following auxiliary pragma demonstrates such a function.

     #pragma aux rtn parm reverse [];


32-bit:  Describing Function Return Information

Using auxiliary pragmas, you can describe the way functions are to return values.  This is particularly useful when interfacing to functions that have been compiled by other compilers or functions written in other programming languages.

The general form of an auxiliary pragma that describes the way a function returns its value is the following.

     #pragma aux sym value {no8087 | reg_set | struct_info} [;]

     struct_info ::= struct {float | struct | (routine | caller) | reg_set}

where

description

sym

is a function name.

reg_set

is called a register set.  The register sets specify the registers that are to be used for argument passing.  A register set is a list of registers separated by spaces and enclosed in square brackets.


32-bit:  Returning Function Values in Registers

The following form of the auxiliary pragma can be used to specify the registers that are to be used to return a function's value.

     #pragma aux sym value reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

Note that the method described below for returning values of type float or double is supported only when the "fpc" option is used.

Depending on the type of the return value, only certain registers are allowed in reg_set.

1-byte

For 1-byte return values, only the following registers are allowed:  AL, AH, DL, DH, BL, BH, CL or CH.  If no register set is specified, register AL will be used.

2-byte

For 2-byte return values, only the following registers are allowed:  AX, DX, BX, CX, SI or DI.  If no register set is specified, register AX will be used.

4-byte

For 4-byte return values (including near pointers), only the following register are allowed:  EAX, EDX, EBX, ECX, ESI or EDI.  If no register set is specified, register EAX will be used.  This form of the auxiliary pragma is legal for functions of type float when using the "fpc" option only.

far pointer

For functions that return far pointers, the following register pairs are allowed:  DX:EAX, CX:EBX, CX:EAX, CX:ESI, DX:EBX, DI:EAX, CX:EDI, DX:ESI, DI:EBX, SI:EAX, CX:EDX, DX:EDI, DI:ESI, SI:EBX, BX:EAX, FS:ECX, FS:EDX, FS:EDI, FS:ESI, FS:EBX, FS:EAX, GS:ECX, GS:EDX, GS:EDI, GS:ESI, GS:EBX, GS:EAX, DS:ECX, DS:EDX, DS:EDI, DS:ESI, DS:EBX, DS:EAX, ES:ECX, ES:EDX, ES:EDI, ES:ESI, ES:EBX or ES:EAX.  If no register set is specified, the registers DX:EAX will be used.

8-byte

For 8-byte return values (including functions of type double), only the following register pairs are allowed:  EDX:EAX, ECX:EBX, ECX:EAX, ECX:ESI, EDX:EBX, EDI:EAX, ECX:EDI, EDX:ESI, EDI:EBX, ESI:EAX, ECX:EDX, EDX:EDI, EDI:ESI, ESI:EBX or EBX:EAX.  If no register set is specified, the registers EDX:EAX will be used.  This form of the auxiliary pragma is legal for functions of type double when using the "fpc" option only.

Notes:

1.	An empty register set is not allowed.

2.	If you are compiling for a memory model which has a small data model, any of the above register combinations containing register DS becomes illegal.  In a small data model, segment register DS must remain unchanged as it points to the program's data segment.

3.	If you are compiling for the flat memory model, any register combination containing DS or ES becomes illegal.  In a flat memory model, code and data reside in the same segment.  Segment registers DS and ES point to this segment and must remain unchanged.


32-bit:  Returning Structures

Typically, structures are not returned in registers.  Instead, the caller allocates space on the stack for the return value and sets register ESI to point to it.  The called routine then places the return value at the location pointed to by register ESI.

The following form of the auxiliary pragma can be used to specify the register that is to be used to point to the return value.

     #pragma aux sym value struct (caller|routine) reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

"caller" specifies that the caller will allocate memory for the return value.  The address of the memory allocated for the return value is placed in the register specified in the register set by the caller before the function is called.  If an empty register set is specified, the address of the memory allocated for the return value will be pushed on the stack immediately before the call and will be returned in register EAX by the called routine.

"routine" specifies that the called routine will allocate memory for the return value.  Upon returning to the caller, the register specified in the register set will contain the address of the return value.  An empty register set is not allowed.

Only the following registers are allowed in the register set:  EAX, EDX, EBX, ECX, ESI or EDI.  Note that in a big data model, the address in the return register is assumed to be in the segment specified by the value in the SS segment register.

If the size of the structure being returned is 1, 2 or 4 bytes, it will be returned in registers.  The return register will be selected from the register set in the following way.

1.	A 1-byte structure will be returned in one of the following registers:  AL, AH, DL, DH, BL, BH, CL or CH.  If no register set is specified, register AL will be used.

2.	A 2-byte structure will be returned in one of the following registers:  AX, DX, BX, CX, SI or DI.  If no register set is specified, register AX will be used.

3.	A 4-byte structure will be returned in one of the following registers:  EAX, EDX, EBX, ECX, ESI or EDI.  If no register set is specified, register EAX will be used.

The following form of the auxiliary pragma can be used to specify that structures whose size is 1, 2 or 4 bytes are not to be returned in registers.  Instead, the caller will allocate space on the stack for the structure return value and point register ESI to it.

     #pragma aux sym value struct struct [;]

where

description

sym

is a function name.


32-bit:  Returning Floating-Point Data

There are a few ways available for specifying how the value for a function whose type is float or double is to be returned.

The following form of the auxiliary pragma can be used to specify that function return values whose type is float or double are not to be returned in registers.  Instead, the caller will allocate space on the stack for the return value and point register ESI to it.

     #pragma aux sym value struct float [;]

where

description

sym

is a function name.

In other words, floating-point values are to be returned in the same way structures are returned.

The following form of the auxiliary pragma can be used to specify that function return values whose type is float or double are not to be returned in 80x87 registers when compiling with the "fpi" or "fpi87" option.  Instead, the value will be returned in 80x86 registers.  This is the default behaviour for the "fpc" option.  Function return values whose type is float will be returned in register EAX.  Function return values whose type is double will be returned in registers EDX:EAX.  This is the default method for the "fpc" option.

     #pragma aux sym value no8087 [;]

where

description

sym

is a function name.

The following form of the auxiliary pragma can be used to specify that function return values whose type is float or double are to be returned in ST(0) when compiling with the "fpi" or "fpi87" option.  This form of the auxiliary pragma is not legal for the "fpc" option.

     #pragma aux sym value [8087] [;]

where

description

sym

is a function name.


32-bit:  A Function that Never Returns

The following form of the auxiliary pragma can be used to describe a function that does not return to the caller.

     #pragma aux sym aborts [;]

where

description

sym

is a function name.

Consider the following example.

     #pragma aux exitrtn aborts;

     extern void exitrtn(void);

     void rtn()

       {

         exitrtn();

       }

exitrtn is defined to be a function that does not return.  For example, it may call exit to return to the system.  In this case, Open Watcom C/C++ generates a "jmp" instruction instead of a "call" instruction to invoke exitrtn.


32-bit:  Describing How Functions Use Memory

The following form of the auxiliary pragma can be used to describe a function that does not modify any memory (i.e., global or static variables) that is used directly or indirectly by the caller.

     #pragma aux sym modify nomemory [;]

where

description

sym

is a function name.

Consider the following example.

     #pragma off (check_stack);

     extern void myrtn(void);

     int i = { 1033 };

     extern Rtn() {

         while( i < 10000 ) {

             i += 383;

         }

         myrtn();

         i += 13143;

     };

To compile the above program, "rtn.c", we issue the following command.

     C>wcc rtn /oai /d1

     C>wpp rtn /oai /d1

     C>wcc386 rtn /oai /d1

     C>wpp386 rtn /oai /d1

For illustrative purposes, we omit loop optimizations from the list of code optimizations that we want the compiler to perform.  The "d1" compiler option is specified so that the object file produced by Open Watcom C/C++ contains source line information.

We can generate a file containing a disassembly of rtn.obj by issuing the following command.

     C>wdis rtn /l /s /r

The "s" option is specified so that the listing file produced by the Open Watcom Disassembler contains source lines taken from rtn.c.  The listing file rtn.lst appears as follows.

     Module: rtn.c

     Group: 'DGROUP' CONST,_DATA

     Segment: '_TEXT' BYTE USE32  00000036 bytes

     #pragma off (check_stack);

     extern void myrtn(void);

     int i = { 1033 };

     extern Rtn() {

      0000  52                Rtn_            push    EDX

      0001  8b 15 00 00 00 00                 mov     EDX,_i

         while( i < 10000 ) {

      0007  81 fa 10 27 00 00 L1              cmp     EDX,00002710H

      000d  7d 08                             jge     L2

             i += 383;

         }

      000f  81 c2 7f 01 00 00                 add     EDX,0000017fH

      0015  eb f0                             jmp     L1

         myrtn();

      0017  89 15 00 00 00 00 L2              mov     _i,EDX

      001d  e8 00 00 00 00                    call    myrtn_

      0022  8b 15 00 00 00 00                 mov     EDX,_i

         i += 13143;

      0028  81 c2 57 33 00 00                 add     EDX,00003357H

      002e  89 15 00 00 00 00                 mov     _i,EDX

     }

      0034  5a                                pop     EDX

      0035  c3                                ret

     No disassembly errors

     ------------------------------------------------------------

     Segment: '_DATA' WORD USE32  00000004 bytes

      0000  09 04 00 00             _i              - ....

     No disassembly errors

     ------------------------------------------------------------

Let us add the following auxiliary pragma to the source file.

     #pragma aux myrtn modify nomemory;

If we compile the source file with the above pragma and disassemble the object file using the Open Watcom Disassembler, we get the following listing file.

     Module: rtn.c

     Group: 'DGROUP' CONST,_DATA

     Segment: '_TEXT' BYTE USE32  00000030 bytes

     #pragma off (check_stack);

     #pragma aux myrtn modify nomemory;

     extern void myrtn(void);

     int i = { 1033 };

     extern Rtn() {

      0000  52                Rtn_            push    EDX

      0001  8b 15 00 00 00 00                 mov     EDX,_i

         while( i < 10000 ) {

      0007  81 fa 10 27 00 00 L1              cmp     EDX,00002710H

      000d  7d 08                             jge     L2

             i += 383;

         }

      000f  81 c2 7f 01 00 00                 add     EDX,0000017fH

      0015  eb f0                             jmp     L1

         myrtn();

      0017  89 15 00 00 00 00 L2              mov     _i,EDX

      001d  e8 00 00 00 00                    call    myrtn_

         i += 13143;

      0022  81 c2 57 33 00 00                 add     EDX,00003357H

      0028  89 15 00 00 00 00                 mov     _i,EDX

     }

      002e  5a                                pop     EDX

      002f  c3                                ret

     No disassembly errors

     ------------------------------------------------------------

     Segment: '_DATA' WORD USE32  00000004 bytes

      0000  09 04 00 00             _i              - ....

     No disassembly errors

     ------------------------------------------------------------

Notice that the value of i is in register EDX after completion of the "while" loop.  After the call to myrtn, the value of i is not loaded from memory into a register to perform the final addition.  The auxiliary pragma informs the compiler that myrtn does not modify any memory (i.e., global or static variables) that is used directly or indirectly by Rtn and hence register EDX contains the correct value of i.

The preceding auxiliary pragma deals with routines that modify memory.  Let us consider the case where routines reference memory.  The following form of the auxiliary pragma can be used to describe a function that does not reference any memory (i.e., global or static variables) that is used directly or indirectly by the caller.

     #pragma aux sym parm nomemory modify nomemory [;]

where

description

sym

is a function name.

Notes:

1.	You must specify both "parm nomemory" and "modify nomemory".

Let us replace the auxiliary pragma in the above example with the following auxiliary pragma.

     #pragma aux myrtn parm nomemory modify nomemory;

If you now compile our source file and disassemble the object file using WDIS, the result is the following listing file.

     Module: rtn.c

     Group: 'DGROUP' CONST,_DATA

     Segment: '_TEXT' BYTE USE32  0000002a bytes

     #pragma off (check_stack);

     #pragma aux myrtn parm nomemory modify nomemory;

     extern void myrtn(void);

     int i = { 1033 };

     extern Rtn() {

      0000  52                Rtn_            push    EDX

      0001  8b 15 00 00 00 00                 mov     EDX,_i

         while( i < 10000 ) {

      0007  81 fa 10 27 00 00 L1              cmp     EDX,00002710H

      000d  7d 08                             jge     L2

             i += 383;

         }

      000f  81 c2 7f 01 00 00                 add     EDX,0000017fH

      0015  eb f0                             jmp     L1

         myrtn();

      0017  e8 00 00 00 00    L2              call    myrtn_

         i += 13143;

      001c  81 c2 57 33 00 00                 add     EDX,00003357H

      0022  89 15 00 00 00 00                 mov     _i,EDX

     }

      0028  5a                                pop     EDX

      0029  c3                                ret

     No disassembly errors

     ------------------------------------------------------------

     Segment: '_DATA' WORD USE32  00000004 bytes

      0000  09 04 00 00             _i              - ....

     No disassembly errors

     ------------------------------------------------------------

Notice that after completion of the "while" loop we did not have to update i with the value in register EDX before calling myrtn.  The auxiliary pragma informs the compiler that myrtn does not reference any memory (i.e., global or static variables) that is used directly or indirectly by myrtn so updating i was not necessary before calling myrtn.


32-bit:  Describing the Registers Modified by a Function

The following form of the auxiliary pragma can be used to describe the registers that a function will use without saving.

     #pragma aux sym modify [exact] reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

Specifying a register set informs Open Watcom C/C++ that the registers belonging to the register set are modified by the function.  That is, the value in a register before calling the function is different from its value after execution of the function.

Registers that are used to pass arguments are assumed to be modified and hence do not have to be saved and restored by the called function.  Also, since the EAX register is frequently used to return a value, it is always assumed to be modified.  If necessary, the caller will contain code to save and restore the contents of registers used to pass arguments.  Note that saving and restoring the contents of these registers may not be necessary if the called function does not modify them.  The following form of the auxiliary pragma can be used to describe exactly those registers that will be modified by the called function.

     #pragma aux sym modify exact reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set.

The above form of the auxiliary pragma tells Open Watcom C/C++ not to assume that the registers used to pass arguments will be modified by the called function.  Instead, only the registers specified in the register set will be modified.  This will prevent generation of the code which unnecessarily saves and restores the contents of the registers used to pass arguments.

Also, any registers that are specified in the value register set are assumed to be unmodified unless explicitly listed in the exact register set.  In the following example, the code generator will not generate code to save and restore the value of the stack pointer register since we have told it that "GetSP" does not modify any register whatsoever.

Example:

     unsigned GetSP(void);

     #if defined(__386__)

     #pragma aux GetSP = value [esp] modify exact [];

     #else

     #pragma aux GetSP = value [sp] modify exact [];

     #endif


32-bit:  An Example

As mentioned in an earlier section, the following pragma defines the calling convention for functions compiled by MetaWare's High C compiler.

     #pragma aux HIGH_C "*"                                 \

                        parm caller []                      \

                        value no8087                        \

                        modify [eax ecx edx fs gs];

Note that register ES must also be specified in the "modify" register set when using a memory model with a non-small data model.  Let us discuss this pragma in detail.

"*"

specifies that all function and variable names appear in object form as they do in source form.

parm caller []

specifies that all arguments are to be passed on the stack (an empty register set was specified) and the caller will remove the arguments from the stack.

value no8087

specifies that floating-point values are to be returned using 80x86 registers and not 80x87 floating-point registers.

modify [eax ecx edx fs gs]

specifies that registers EAX, ECX, EDX, FS and GS are not preserved by the called routine.

Note that the default method of returning integer values is used; 1-byte characters are returned in register AL, 2-byte integers are returned in register AX, and 4-byte integers are returned in register EAX.


32-bit:  Auxiliary Pragmas and the 80x87

This section deals with those aspects of auxiliary pragmas that are specific to the 80x87.  The discussion in this chapter assumes that one of the "fpi" or "fpi87" options is used to compile functions.  The following areas are affected by the use of these options.

1.	passing floating-point arguments to functions,

2.	returning floating-point values from functions and

3.	which 80x87 floating-point registers are allowed to be modified by the called routine.


32-bit:  Using the 80x87 to Pass Arguments

By default, floating-point arguments are passed on the 80x86 stack.  The 80x86 registers are never used to pass floating-point arguments when a function is compiled with the "fpi" or "fpi87" option.  However, they can be used to pass arguments whose type is not floating-point such as arguments of type "int".

The following form of the auxiliary pragma can be used to describe the registers that are to be used to pass arguments to functions.

     #pragma aux sym parm {reg_set} [;]

where

description

sym

is a function name.

reg_set

is a register set.  The register set can contain 80x86 registers and/or the string "8087".

Notes:

1.	If an empty register set is specified, all arguments, including floating-point arguments, will be passed on the 80x86 stack.

When the string "8087" appears in a register set, it simply means that floating-point arguments can be passed in 80x87 floating-point registers if the source file is compiled with the "fpi" or "fpi87" option.  Before discussing argument passing in detail, some general notes on the use of the 80x87 floating-point registers are given.

The 80x87 contains 8 floating-point registers which essentially form a stack.  The stack pointer is called ST and is a number between 0 and 7 identifying which 80x87 floating-point register is at the top of the stack.  ST is initially 0.  80x87 instructions reference these registers by specifying a floating-point register number.  This number is then added to the current value of ST.  The sum (taken modulo 8) specifies the 80x87 floating-point register to be used.  The notation ST(n), where "n" is between 0 and 7, is used to refer to the position of an 80x87 floating-point register relative to ST.

When a floating-point value is loaded onto the 80x87 floating-point register stack, ST is decremented (modulo 8), and the value is loaded into ST(0).  When a floating-point value is stored and popped from the 80x87 floating-point register stack, ST is incremented (modulo 8) and ST(1) becomes ST(0).  The following illustrates the use of the 80x87 floating-point registers as a stack, assuming that the value of ST is 4 (4 values have been loaded onto the 80x87 floating-point register stack).

                 +----------------+

           0     | 4th from top   |  ST(4)

                 +----------------+

           1     | 5th from top   |  ST(5)

                 +----------------+

           2     | 6th from top   |  ST(6)

                 +----------------+

           3     | 7th from top   |  ST(7)

                 +----------------+

     ST -> 4     | top of stack   |  ST(0)

                 +----------------+

           5     | 1st from top   |  ST(1)

                 +----------------+

           6     | 2nd from top   |  ST(2)

                 +----------------+

           7     | 3rd from top   |  ST(3)

                 +----------------+

Starting with version 9.5, the Open Watcom compilers use all eight of the 80x87 registers as a stack.  The initial state of the 80x87 register stack is empty before a program begins execution.

Note:

For compatibility with code compiled with version 9.0 and earlier, you can compile with the "fpr" option.  In this case only four of the eight 80x87 registers are used as a stack.  These four registers were used to pass arguments.  The other four registers form what was called the 80x87 cache.  The cache was used for local floating-point variables.  The state of the 80x87 registers before a program began execution was as follows.

1.	The four 80x87 floating-point registers that form the stack are uninitialized.

2.	The four 80x87 floating-point registers that form the 80x87 cache are initialized with zero.

Hence, initially the 80x87 cache was comprised of ST(0), ST(1), ST(2) and ST(3).  ST had the value 4 as in the above diagram.  When a floating-point value was pushed on the stack (as is the case when passing floating-point arguments), it became ST(0) and the 80x87 cache was comprised of ST(1), ST(2), ST(3) and ST(4).  When the 80x87 stack was full, ST(0), ST(1), ST(2) and ST(3) formed the stack and ST(4), ST(5), ST(6) and ST(7) formed the 80x87 cache.  Version 9.5 and later no longer use this strategy.

The rules for passing arguments are as follows.

1.	If the argument is not floating-point, use the procedure described earlier in this chapter.

2.	If the argument is floating-point, and a previous argument has been assigned a position on the 80x86 stack (instead of the 80x87 stack), the floating-point argument is also assigned a position on the 80x86 stack.  Otherwise proceed to the next step.

3.	If the string "8087" appears in a register set in the pragma, and if the 80x87 stack is not full, the floating-point argument is assigned floating-point register ST(0) (the top element of the 80x87 stack).  The previous top element (if there was one) is now in ST(1).  Since arguments are pushed on the stack from right to left, the leftmost floating-point argument will be in ST(0).  Otherwise the floating-point argument is assigned a position on the 80x86 stack.

Consider the following example.

     #pragma aux myrtn parm [8087];

     void main()

     {

         float    x;

         double   y;

         int      i;

         long int j;

         x = 7.7;

         i = 7;

         y = 77.77;

         j = 77;

         myrtn( x, i, y, j );

     }

myrtn is an assembly language function that requires four arguments.  The first argument of type float (4 bytes), the second argument is of type int (4 bytes), the third argument is of type double (8 bytes) and the fourth argument is of type long int (4 bytes).  These arguments will be passed to myrtn in the following way.

1.	Since "8087" was specified in the register set, the first argument, being of type float, will be passed in an 80x87 floating-point register.

2.	The second argument will be passed on the stack since no 80x86 registers were specified in the register set.

3.	The third argument will also be passed on the stack.  Remember the following rule:  once an argument is assigned a position on the stack, all remaining arguments will be assigned a position on the stack.  Note that the above rule holds even though there are some 80x87 floating-point registers available for passing floating-point arguments.

4.	The fourth argument will also be passed on the stack.

Let us change the auxiliary pragma in the above example as follows.

     #pragma aux myrtn parm [eax 8087];

The arguments will now be passed to myrtn in the following way.

1.	Since "8087" was specified in the register set, the first argument, being of type float will be passed in an 80x87 floating-point register.

2.	The second argument will be passed in register EAX, exhausting the set of available 80x86 registers for argument passing.

3.	The third argument, being of type double, will also be passed in an 80x87 floating-point register.

4.	The fourth argument will be passed on the stack since no 80x86 registers remain in the register set.


32-bit:  Using the 80x87 to Return Function Values

The following form of the auxiliary pragma can be used to describe a function that returns a floating-point value in ST(0).

     #pragma aux sym value reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set containing the string "8087", i.e.  [8087].


32-bit:  Preserving 80x87 Floating-Point Registers Across Calls

The code generator assumes that all eight 80x87 floating-point registers are available for use within a function unless the "fpr" option is used to generate backward compatible code (older Open Watcom compilers used four registers as a cache).  The following form of the auxiliary pragma specifies that the floating-point registers in the 80x87 cache may be modified by the specified function.

     #pragma aux sym modify reg_set [;]

where

description

sym

is a function name.

reg_set

is a register set containing the string "8087", i.e.  [8087].

This instructs Open Watcom C/C++ to save any local variables that are located in the 80x87 cache before calling the specified routine.


In-line Assembly Language

The chapters entitled 16-bit Pragmas and 32-bit Pragmas briefly describe the use of the auxiliary pragma to create a sequence of assembly language instructions that can be placed anywhere executable C/C++ statements can appear in your source code.  This chapter is devoted to an in-depth look at in-line assembly language programming.

The reasons for resorting to in-line assembly code are varied:

•	Speed - You may be interested in optimizing a heavily-used section of code.

•	Size - You may wish to optimize a module for size by replacing a library function call with a direct system call.

•	Architecture - You may want to access certain features of the Intel x86 architecture that cannot be done so with C/C++ statements.

There are also some reasons for not resorting to in-line assembly code.

•	Portability - The code is not portable to different architectures.

•	Optimization - Sometimes an optimizing compiler can do a better job of arranging the instruction stream so that it is optimal for a particular processor (such as the 486 or Pentium).


In-line Assembly Language Default Environment

In next table is description of the default in-line assembler environment in dependency on C/C++ compilers CPU switch for x86 target platform.

     Compiler  CPU        FPU        CPU extension

               directive  directive  directives

     --------  ---------  ---------  --------------------------

     -0        .8086      .8087

     -1        .186       .8087

     -2        .286p      .287

     -3        .386p      .387

     -4        .486p      .387

     -5        .586p      .387       .K3D+.MMX

     -6        .686p      .387       .K3D+.MMX+.XMM+.XMM2+.XMM3

This environment can be simply changed by appropriate directives.

Note:

This change is valid only for the block of assembly source code.  After this block, default setting is restored.


In-line Assembly Language Tutorial

Doing in-line assembly is reasonably straight-forward with Open Watcom C/C++ although care must be exercised.  You can generate a sequence of in-line assembly anywhere in your C/C++ code stream.  The first step is to define the sequence of instructions that you wish to place in-line.  The auxiliary pragma is used to do this.  Here is a simple example based on a DOS function call that returns a far pointer to the Double-Byte Character Set (DBCS) encoding table.

Example:

     extern unsigned short far *dbcs_table( void );

     #pragma aux dbcs_table = \

             "mov ax,6300h"   \

             "int 21h"        \

             value   [ds si]  \

             modify  [ax];

To set up the DOS call, the AH register must contain the hexadecimal value "63" (63h).  A DOS function call is invoked by interrupt 21h.  DOS returns a far pointer in DS:SI to a table of byte pairs in the form (start of range, end of range).  On a non-DBCS system, the first pair will be (0,0).  On a Japanese DBCS system, the first pair will be (81h,9Fh).

With each pragma, we define a corresponding function prototype that explains the behaviour of the function in terms of C/C++.  Essentially, it is a function that does not take any arguments and that returns a far pointer to a unsigned short item.

The pragma indicates that the result of this "function" is returned in DS:SI (value [ds si]).  The pragma also indicates that the AX register is modified by the sequence of in-line assembly code (modify [ax]).

Having defined our in-line assembly code, let us see how it is used in actual C code.

Example:

     #include <stdio.h>

     extern unsigned short far *dbcs_table( void );

     #pragma aux dbcs_table = \

             "mov ax,6300h"   \

             "int 21h"        \

             value   [ds si]  \

             modify  [ax];

     void main()

     {

         if( *dbcs_table() != 0 ) {

             /*

                 we are running on a DOS system that

                 supports double-byte characters

             */

             printf( "DBCS supported\n" );

         }

     }

Before you attempt to compile and run this example, consider this:  The program will not work!  At least, it will not work in most 16-bit memory models.  And it doesn't work at all in 32-bit protected mode using a DOS extender.  What is wrong with it?

We can examine the disassembled code for this program in order to see why it does not always work in 16-bit real-mode applications.

         if( *dbcs_table() != 0 ) {

             /*

                 we are running on a DOS system that

                 supports double-byte characters

             */

      0007  b8 00 63                          mov     ax,6300H

      000a  cd 21                             int     21H

      000c  83 3c 00                          cmp     word ptr [si],0000H

      000f  74 0a                             je      L1

             printf( "DBCS supported\n" );

         }

      0011  be 00 00                          mov     si,offset L2

      0014  56                                push    si

      0015  e8 00 00                          call    printf_

      0018  83 c4 02                          add     sp,0002H

     }

After the DOS interrupt call, the DS register has been altered and the code generator does nothing to recover the previous value.  In the small memory model, the contents of the DS register never change (and any code that causes a change to DS must save and restore its value).  It is the programmer's responsibility to be aware of the restrictions imposed by certain memory models especially with regards to the use of segmentation registers.  So we must make a small change to the pragma.

     extern unsigned short far *dbcs_table( void );

     #pragma aux dbcs_table = \

             "push ds"        \

             "mov ax,6300h"   \

             "int 21h"        \

             "mov di,ds"      \

             "pop ds"         \

             value   [di si]  \

             modify  [ax];

If we compile and run this example with a 16-bit compiler, it will work properly.  We can examine the disassembled code for this revised program.

         if( *dbcs_table() != 0 ) {

             /*

                 we are running on a DOS system that

                 supports double-byte characters

             */

      0008  1e                                push    ds

      0009  b8 00 63                          mov     ax,6300H

      000c  cd 21                             int     21H

      000e  8c df                             mov     di,ds

      0010  1f                                pop     ds

      0011  8e c7                             mov     es,di

      0013  26 83 3c 00                       cmp     word ptr es:[si],0000H

      0017  74 0a                             je      L1

             printf( "DBCS supported\n" );

         }

      0019  be 00 00                          mov     si,offset L2

      001c  56                                push    si

      001d  e8 00 00                          call    printf_

      0020  83 c4 02                          add     sp,0002H

If you examine this code, you can see that the DS register is saved and restored by the in-line assembly code.  The code generator, having been informed that the far pointer is returned in (DI:SI), loads up the ES register from DI in order to reference the far data correctly.

That takes care of the 16-bit real-mode case.  What about 32-bit protected mode?  When using a DOS extender, you must examine the accompanying documentation to see if the system call that you wish to make is supported by the DOS extender.  One of the reasons that this particular DOS call is not so clear-cut is that it returns a 16-bit real-mode segment:offset pointer.  A real-mode pointer must be converted by the DOS extender into a protected-mode pointer in order to make it useful.  As it turns out, neither the Tenberry Software DOS/4G(W) nor Phar Lap DOS extenders support this particular DOS call (although others may).  The issues with each DOS extender are complex enough that the relative merits of using in-line assembly code are not worth it.  We present an excerpt from the final solution to this problem.

Example:

     #ifndef __386__

     extern unsigned short far *dbcs_table( void );

     #pragma aux dbcs_table = \

             "push ds"        \

             "mov ax,6300h"   \

             "int 21h"        \

             "mov di,ds"      \

             "pop ds"         \

             value   [di si]  \

             modify  [ax];

     #else

     unsigned short far * dbcs_table( void )

     {

         union REGPACK       regs;

         static short        dbcs_dummy = 0;

         memset( &regs, 0, sizeof( regs ) );

         if( _IsPharLap() ) {

             PHARLAP_block pblock;

             memset( &pblock, 0, sizeof( pblock ) );

             pblock.real_eax = 0x6300;       /* get DBCS vector table */

             pblock.int_num = 0x21;          /* DOS call */

             regs.x.eax = 0x2511;            /* issue real-mode interrupt */

             regs.x.edx = FP_OFF( &pblock ); /* DS:EDX -> parameter block */

             regs.w.ds = FP_SEG( &pblock );

             intr( 0x21, &regs );

             return( firstmeg( pblock.real_ds, regs.w.si ) );

         } else if( _IsDOS4G() ) {

             DPMI_block dblock;

             memset( &dblock, 0, sizeof( dblock ) );

             dblock.eax = 0x6300;            /* get DBCS vector table */

             regs.w.ax = 0x300;              /* DPMI Simulate R-M intr */

             regs.h.bl = 0x21;               /* DOS call */

             regs.h.bh = 0;                  /* flags */

             regs.w.cx = 0;                  /* # bytes from stack */

             regs.x.edi = FP_OFF( &dblock );

             regs.x.es = FP_SEG( &dblock );

             intr( 0x31, &regs );

             return( firstmeg( dblock.ds, dblock.esi ) );

         } else {

             return( &dbcs_dummy );

         }

     }

     #endif

The 16-bit version will use in-line assembly code but the 32-bit version will use a C function that has been crafted to work with both Tenberry Software DOS/4G(W) and Phar Lap DOS extenders.  The firstmeg function used in the example is shown below.

     #define REAL_SEGMENT    0x34

     void far *firstmeg( unsigned segment, unsigned offset )

     {

         void far    *meg1;

         if( _IsDOS4G() ) {

             meg1 = MK_FP( FP_SEG( &meg1 ), ( segment << 4 ) + offset );

         } else {

             meg1 = MK_FP( REAL_SEGMENT, ( segment << 4 ) + offset );

         }

         return( meg1 );

     }

We have taken a brief look at two features of the auxiliary pragma, the "modify" and "value" attributes.

The "modify" attribute describes those registers that are modified by the execution of the sequence of in-line code.  You usually have two choices here; you can save/restore registers that are affected by the code sequence in which case they need not appear in the modify list or you can let the code generator handle the fact that the registers are modified by the code sequence.  When you invoke a system function (such as a DOS or BIOS call), you should be careful about any side effects that the call has on registers.  If a register is modified by a call and you have not listed it in the modify list or saved/restored it, this can have a disastrous affect on the rest of the code in the function where you are including the in-line code.

The "value" attribute describes the register or registers in which a value is returned (we use the term "returned", not in the sense that a function returns a value, but in the sense that a result is available after execution of the code sequence).

This leads the discussion into the third feature of the auxiliary pragma, the feature that allows us to place the results of C expressions into specific registers as part of the "setup" for the sequence of in-line code.  To illustrate this, let us look at another example.

Example:

     extern void BIOSSetCurPos( unsigned short __rowcol,

                                unsigned char __page );

     #pragma aux BIOSSetCurPos =     \

             "push bp"               \

             "mov ah,2"              \

             "int 10h"               \

             "pop bp"                \

             parm   [dx] [bh]        \

             modify [ah];

The "parm" attribute specifies the list of registers into which values are to be placed as part of the prologue to the in-line code sequence.  In the above example, the "set cursor position" function requires three pieces of information.  It requires that the cursor row value be placed in the DH register, that the cursor column value be placed in the DL register, and that the screen page number be placed in the BH register.  In this example, we have decided to combine the row and column information into a single "argument" to the function.  Note that the function prototype for BIOSSetCurPos is important.  It describes the types and number of arguments to be set up for the in-line code.  It also describes the type of the return value (in this case there is none).

Once again, having defined our in-line assembly code, let us see how it is used in actual C code.

Example:

     #include <stdio.h>

     extern void BIOSSetCurPos( unsigned short __rowcol,

                                unsigned char __page );

     #pragma aux BIOSSetCurPos =     \

             "push bp"               \

             "mov ah,2"              \

             "int 10h"               \

             "pop bp"                \

             parm   [dx] [bh]        \

             modify [ah];

     void main()

     {

         BIOSSetCurPos( (5 << 8) | 20, 0 );

         printf( "Hello world\n" );

     }

To see how the code generator set up the register values for the in-line code, let us take a look at the disassembled code.

         BIOSSetCurPos( (5 << 8) | 20, 0 );

      0008  ba 14 05                          mov     dx,0514H

      000b  30 ff                             xor     bh,bh

      000d  55                                push    bp

      000e  b4 02                             mov     ah,02H

      0010  cd 10                             int     10H

      0012  5d                                pop     bp

As we expected, the result of the expression for the row and column is placed in the DX register and the page number is placed in the BH register.  The remaining instructions are our in-line code sequence.

Although our examples have been simple, you should be able to generalize them to your situation.

To review, the "parm", "value" and "modify" attributes are used to:

1.	convey information to the code generator about the way data values are to be placed in registers in preparation for the code burst (parm),

2.	convey information to the code generator about the result, if any, from the code burst (value), and

3.	convey information to the code generator about any side effects to the registers after the code burst has executed (modify).  It is important to let the code generator know all of the side effects on registers when the in-line code is executed; otherwise it assumes that all registers, other than those used for parameters, are preserved.  In our examples, we chose to push/pop some of the registers that are modified by the code burst.


Labels in In-line Assembly Code

Labels can be used in in-line assembly code.  Here is an example.

Example:

     extern void _disable_video( unsigned );

     #pragma aux _disable_video =    \

      "again: in al,dx"              \

             "test al,8"             \

             "jz again"              \

             "mov dx,03c0h"          \

             "mov al,11h"            \

             "out dx,al"             \

             "mov al,0"              \

             "out dx,al"             \

             parm [dx]               \

             modify [al dx];


Variables in In-line Assembly Code

To finish our discussion, we provide examples that illustrate the use of variables in the in-line assembly code.  The following example illustrates the use of static variable references in the auxiliary pragma.

Example:

     #include <stdio.h>

     static short         _rowcol;

     static unsigned char _page;

     extern void BIOSSetCurPos( void );

     #pragma aux BIOSSetCurPos =     \

             "mov  dx,_rowcol"       \

             "mov  bh,_page"         \

             "push bp"               \

             "mov ah,2"              \

             "int 10h"               \

             "pop bp"                \

             modify [ah bx dx];

     void main()

     {

         _rowcol = (5 << 8) | 20;

         _page = 0;

         BIOSSetCurPos();

         printf( "Hello world\n" );

     }

The only rule to follow here is that the auxiliary pragma must be defined after the variables are defined.  The in-line assembler is passed information regarding the sizes of variables so they must be defined first.

If we look at a fragment of the disassembled code, we can see the result.

         _rowcol = (5 << 8) | 20;

      0008  c7 06 00 00 14 05                 mov     word ptr __rowcol,0514H

         _page = 0;

      000e  c6 06 00 00 00                    mov     byte ptr __page,00H

         BIOSSetCurPos();

      0013  8b 16 00 00                       mov     dx,__rowcol

      0017  8a 3e 00 00                       mov     bh,__page

      001b  55                                push    bp

      001c  b4 02                             mov     ah,02H

      001e  cd 10                             int     10H

      0020  5d                                pop     bp

The following example illustrates the use of automatic variable references in the auxiliary pragma.  Again, the auxiliary pragma must be defined after the variables are defined so the pragma is placed in-line with the function.

Example:

     #include <stdio.h>

     void main()

     {

         short         _rowcol;

         unsigned char _page;

         extern void BIOSSetCurPos( void );

     #   pragma aux  BIOSSetCurPos = \

             "mov  dx,_rowcol"       \

             "mov  bh,_page"         \

             "push bp"               \

             "mov ah,2"              \

             "int 10h"               \

             "pop bp"                \

             modify [ah bx dx];

         _rowcol = (5 << 8) | 20;

         _page = 0;

         BIOSSetCurPos();

         printf( "Hello world\n" );

     }

If we look at a fragment of the disassembled code, we can see the result.

         _rowcol = (5 << 8) | 20;

      000e  c7 46 fc 14 05                    mov     word ptr -4H[bp],0514H

         _page = 0;

      0013  c6 46 fe 00                       mov     byte ptr -2H[bp],00H

         BIOSSetCurPos();

      0017  8b 96 fc ff                       mov     dx,-4H[bp]

      001b  8a be fe ff                       mov     bh,-2H[bp]

      001f  55                                push    bp

      0020  b4 02                             mov     ah,02H

      0022  cd 10                             int     10H

      0024  5d                                pop     bp

You should try to avoid references to automatic variables as illustrated by this last example.  Referencing automatic variables in this manner causes them to be marked as volatile and the optimizer will not be able to do a good job of optimizing references to these variables.


In-line Assembly Language using _asm

There is an alternative to Open Watcom's auxiliary pragma method for creating in-line assembly code.  You can use one of the _asm or __asm keywords to imbed assembly code into the generated code.  The following is a revised example of the cursor positioning example introduced above.

Example:

     #include <stdio.h>

     void main()

     {

         unsigned short _rowcol;

         unsigned char _page;

         _rowcol = (5 << 8) | 20;

         _page = 0;

         _asm {

             mov     dx,_rowcol

             mov     bh,_page

             push    bp

             mov     ah,2

             int     10h

             pop     bp

         };

         printf( "Hello world\n" );

     }

The assembly language sequence can reference program variables to retrieve or store results.  There are a few incompatibilities between Microsoft and Open Watcom implementation of this directive.

__LOCAL_SIZE

is not supported by Open Watcom C/C++.  This is illustrated in the following example.

Example:

     void main()

     {

         int i;

         int j;

         _asm {

             push    bp

             mov     bp,sp

             sub     sp,__LOCAL_SIZE

         };

     }

structure

references are not supported by Open Watcom C/C++.  This is illustrated in the following example.

Example:

     #include <stdio.h>

     struct rowcol {

         unsigned char col;

         unsigned char row;

     };

     void main()

     {

         struct rowcol _pos;

         unsigned char _page;

         _pos.row = 5;

         _pos.col = 20;

         _page = 0;

         _asm {

             mov     dl,_pos.col

             mov     dh,_pos.row

             mov     bh,_page

             push    bp

             mov     ah,2

             int     10h

             pop     bp

         };

         printf( "Hello world\n" );

     }


In-line Assembly Directives and Opcodes

It is not the intention of this chapter to describe assembly-language programming in any detail.  You should consult a book that deals with this topic.  However, we present a list of the directives, opcodes and register names that are recognized by the assembler built into the compiler's auxiliary pragma processor.

.186           .286           .286c          .286p          .287           .386           .386p          .387           .486           .486p          .586           .586p          .686           .686p          .8086          .8087          byte           db             dd             df             dp             dq             dt             dup            dw             dword          far            .k3d           .mmx           near           .no87          offset         oword          ptr            pword          qword          seg            tbyte          word           .xmm           .xmm2          .xmm3

aaa            aad            aam            aas            adc            add            addpd          addps          addsd          addss          addsubpd       addsubps       and            andnpd         andnps         andpd          andps          arpl           bound          bp             bsf            bsr            bswap          bt             btc            btr            bts            call           callf          cbw            cdq            clc            cld            clflush        cli            clts           cmc            cmova          cmovae         cmovb          cmovbe         cmovc          cmove          cmovg          cmovge         cmovl          cmovle         cmovna         cmovnae        cmovnb         cmovnbe        cmovnc         cmovne         cmovng         cmovnge        cmovnl         cmovnle        cmovno         cmovnp         cmovns         cmovnz         cmovo          cmovp          cmovpe         cmovpo         cmovs          cmovz          cmp            cmpeqpd        cmpeqps        cmpeqsd        cmpeqss        cmplepd        cmpleps        cmplesd        cmpless        cmpltpd        cmpltps        cmpltsd        cmpltss        cmpneqpd       cmpneqps       cmpneqsd       cmpneqss       cmpnlepd       cmpnleps       cmpnlesd       cmpnless       cmpnltpd       cmpnltps       cmpnltsd       cmpnltss       cmpordpd       cmpordps       cmpordsd       cmpordss       cmppd          cmpps          cmps           cmpsb          cmpsd          cmpss          cmpsw          cmpunordpd     cmpunordps     cmpunordsd     cmpunordss     cmpxchg        cmpxchg8b      comisd         comiss         cpuid          cvtdq2pd       cvtdq2ps       cvtpd2dq       cvtpd2pi       cvtpd2ps       cvtpi2pd       cvtpi2ps       cvtps2dq       cvtps2pd       cvtps2pi       cvtsd2si       cvtsd2ss       cvtsi2sd       cvtsi2ss       cvtss2sd       cvtss2si       cvttpd2dq      cvttpd2pi      cvttps2dq      cvttps2pi      cvttsd2si

cvttss2si      cwd            cwde           daa            das            dec            div            divpd          divps          divsd          divss          emms           enter          f2xm1          fabs           fadd           faddp          fbld           fbstp          fchs           fclex          fcmovb         fcmovbe        fcmove         fcmovnb        fcmovnbe       fcmovne        fcmovnu        fcmovu         fcom           fcomi          fcomip         fcomp          fcompp         fcos           fdecstp        fdisi          fdiv           fdivp          fdivr          fdivrp         femms          feni           ffree          fiadd          ficom          ficomp         fidiv          fidivr         fild           fimul          fincstp        finit          fist           fistp          fisttp         fisub          fisubr         flat           fld            fld1           fldcw          fldenv         fldenvd        fldenvw        fldl2e         fldl2t         fldlg2         fldln2         fldpi          fldz           fmul           fmulp          fnclex         fndisi         fneni          fninit         fnop           fnrstor        fnrstord       fnrstorw       fnsave         fnsaved        fnsavew        fnstcw         fnstenv        fnstenvd       fnstenvw       fnstsw         fpatan         fprem          fprem1         fptan          frndint        frstor         frstord        frstorw        fsave          fsaved         fsavew         fscale         fsetpm         fsin           fsincos        fsqrt          fst            fstcw          fstenv         fstenvd        fstenvw        fstp           fstsw          fsub           fsubp          fsubr          fsubrp         ftst           fucom          fucomi         fucomip        fucomp         fucompp        fwait          fxam           fxch           fxrstor        fxsave         fxtract        fyl2x          fyl2xp1        haddpd         haddps         hlt

hsubpd         hsubps         idiv           imul           in             inc            ins            insb           insd           insw           int            into           invd           invlpg         iret           iretd          iretdf         iretf          ja             jae            jb             jbe            jc             jcxz           je             jecxz          jg             jge            jl             jle            jmp            jmpf           jna            jnae           jnb            jnbe           jnc            jne            jng            jnge           jnl            jnle           jno            jnp            jns            jnz            jo             jp             jpe            jpo            js             jz             lahf           lar            lddqu          ldmxcsr        lds            lea            leave          les            lfence         lfs            lgdt           lgs            lidt           lldt           lmsw           lock           lods           lodsb          lodsd          lodsw          loop           loopd          loope          looped         loopew         loopne         loopned        loopnew        loopnz         loopnzd        loopnzw        loopw          loopz          loopzd         loopzw         lsl            lss            ltr            maskmovdqu     maskmovq       maxpd          maxps          maxsd          maxss          mfence         minpd          minps          minsd          minss          monitor        mov            movapd         movaps         movd           movddup        movdq2q        movdqa         movdqu         movhlps        movhpd         movhps         movlhps        movlpd         movlps         movmskpd       movmskps       movntdq        movnti         movntpd        movntps        movntq         movq           movq2dq        movs           movsb          movsd          movshdup       movsldup       movss          movsw          movsx

movupd         movups         movzx          mul            mulpd          mulps          mulsd          mulss          mwait          near           neg            nop            not            or             orpd           orps           out            outs           outsb          outsd          outsw          packssdw       packsswb       packuswb       paddb          paddd          paddq          paddsb         paddsw         paddusb        paddusw        paddw          pand           pandn          pause          pavgb          pavgusb        pavgw          pcmpeqb        pcmpeqd        pcmpeqw        pcmpgtb        pcmpgtd        pcmpgtw        pextrw         pf2id          pf2iw          pfacc          pfadd          pfcmpeq        pfcmpge        pfcmpgt        pfmax          pfmin          pfmul          pfnacc         pfpnacc        pfrcp          pfrcpit1       pfrcpit2       pfrsqit1       pfrsqrt        pfsub          pfsubr         pi2fd          pi2fw          pinsrw         pmaddwd        pmaxsw         pmaxub         pminsw         pminub         pmovmskb       pmulhrw        pmulhuw        pmulhw         pmullw         pmuludq        pop            popa           popad          popf           popfd          por            prefetch       prefetchnta    prefetcht0     prefetcht1     prefetcht2     prefetchw      psadbw         pshufd         pshufhw        pshuflw        pshufw         pslld          pslldq         psllq          psllw          psrad          psraw          psrld          psrldq         psrlq          psrlw          psubb          psubd          psubq          psubsb         psubsw         psubusb        psubusw        psubw          pswapd         punpckhbw      punpckhdq      punpckhqdq     punpckhwd      punpcklbw      punpckldq      punpcklqdq     punpcklwd      push           pusha          pushad         pushd          pushf          pushfd         pushw          pxor           rcl            rcpps          rcpss

rcr            rdmsr          rdpmc          rdtsc          rep            repe           repne          repnz          rept           repz           ret            retd           retf           retfd          retn           rol            ror            rsm            rsqrtps        rsqrtss        sahf           sal            sar            sbb            scas           scasb          scasd          scasw          seta           setae          setb           setbe          setc           sete           setg           setge          setl           setle          setna          setnae         setnb          setnbe         setnc          setne          setng          setnge         setnl          setnle         setno          setnp          setns          setnz          seto           setp           setpe          setpo          sets           setz           sfence         sgdt           shl            shld           short          shr            shrd           shufpd         shufps         sidt           sldt           smsw           sp             sqrtpd         sqrtps         sqrtsd         sqrtss         stc            std            sti            stmxcsr        stos           stosb          stosd          stosw          str            sub            subpd          subps          subsd          subss          sysenter       sysexit        test           ucomisd        ucomiss        unpckhpd       unpckhps       unpcklpd       unpcklps       verr           verw           wait           wbinvd         wrmsr          xadd           xchg           xlat           xlatb          xor            xorpd          xorps

ah             al             ax             bh             bl             bx             ch             cl             cr0            cr2            cr3            cr4            cs             cx             dh             di             dl             dr0            dr1            dr2            dr3            dr6            dr7            ds             dx             eax            ebp            ebx            ecx            edi            edx            es             esi            esp            fs             gs             mm0            mm1            mm2            mm3            mm4            mm5            mm6            mm7            si             ss             st             st0            st1            st2            st3            st4            st5            st6            st7            tr3            tr4            tr5            tr6            tr7            xmm0           xmm1           xmm2           xmm3           xmm4           xmm5           xmm6           xmm7

A separate assembler is also included with this product and is described in the Open Watcom C/C++ Tools User's Guide


Structured Exception Handling

Microsoft-style Structured Exception Handling (SEH) is supported by the Open Watcom C compiler only.  MS SEH is supported under the Win32, Win32s and OS/2 platforms.  You should not confuse SEH with C++ exception handling.  The Open Watcom C++ compiler supports the standard C++ syntax for exception handling.

The following sections introduce some of the aspects of SEH.  For a good description of SEH, please refer to Advanced Windows NT by Jeffrey Richter (Microsoft Press, 1994).  You may also wish to read the article "Clearer, More Comprehensive Error Processing with Win32 Structured Exception Handling" by Kevin Goodman in the January, 1994 issue of Microsoft Systems Journal.


Termination Handlers

We begin our look at SEH with a simple model.  In this model, there are two blocks of code - the "guarded" block and the "termination" block.  The termination code is guaranteed to be executed regardless of how the "guarded" block of code is exited (including execution of any "return" statement).

     _try {

         /* guarded code */

         .

         .

         .

     }

     _finally {

         /* termination handler */

         .

         .

         .

     }

The _finally block of code is guaranteed to be executed no matter how the guarded block is exited ( break , continue , return , goto , or longjmp ).  Exceptions to this are calls to abort , exit or _exit which terminate the execution of the process.

There can be no intervening code between try and finally blocks.

The following is a contrived example of the use of _try and _finally .

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     int docopy( char *in, char *out )

     {

       FILE        *in_file = NULL;

       FILE        *out_file = NULL;

       char        buffer[256];

       _try {

         in_file = fopen( in, "r" );

         if( in_file == NULL ) return( EXIT_FAILURE );

         out_file = fopen( out, "w" );

         if( out_file == NULL ) return( EXIT_FAILURE );

         while( fgets((char *)buffer, 255, in_file) != NULL ) {

           fputs( (char *)buffer, out_file );

         }

       }

       _finally {

         if( in_file != NULL ) {

           printf( "Closing input file\n" );

           fclose( in_file );

         }

         if( out_file != NULL ) {

           printf( "Closing output file\n" );

           fclose( out_file );

         }

         printf( "End of processing\n" );

       }

       return( EXIT_SUCCESS );

     }

     void main( int argc, char **argv )

     {

       if( argc < 3 ) {

         printf( "Usage: mv [in_filename] [out_filename]\n" );

         exit( EXIT_FAILURE );

       }

       exit( docopy( argv[1], argv[2] ) );

     }

The try block ignores the messy details of what to do when either one of the input or output files cannot be opened.  It simply tests whether a file can be opened and quits if it cannot.  The finally block ensures that the files are closed if they were opened, releasing the resources associated with open files.  This simple example could have been written in C without the use of SEH.

There are two ways to enter the finally block.  One way is to exit the try block using a statement like return .  The other way is to fall through the end of the try block and into the finally block (the normal execution flow for this program).  Any code following the finally block is only executed in the second case.  You can think of the finally block as a special function that is invoked whenever an exit (other than falling out the bottom) is attempted from a corresponding try block.

More formally stated, a local unwind occurs when the system executes the contents of a finally block because of the premature exit of code in a try block.

  Note:  Kevin Goodman describes "unwinds" in his article.  "There are two types of unwinds:  global and local.  A global unwind occurs when there are nested functions and an exception takes place.  A local unwind takes place when there are multiple handlers within one function.  Unwinding means that the stack is going to be clean by the time your handler's code gets executed."

The try/finally structure is a rejection mechanism which is useful when a set of statements is to be conditionally chosen for execution, but not all of the conditions required to make the selection are available beforehand.  It is an extension to the C language.  You start out with the assumption that a certain task can be accomplished.  You then introduce statements into the code that test your hypothesis.  The try block consists of the code that you assume, under normal conditions, will succeed.  Statements like if ...  return can be used as tests.  Execution begins with the statements in the try block.  If a condition is detected which indicates that the assumption of a normal state of affairs is wrong, a return statement may be executed to cause control to be passed to the statements in the finally block.  If the try block completes execution without executing a return statement (i.e., all statements are executed up to the final brace), then control is passed to the first statement following the try block (i.e., the first statement in the finally block).

In the following example, two sets of codes and letters are read in and some simple sequence checking is performed.  If a sequence error is detected, an error message is printed and processing terminates; otherwise the numbers are processed and another pair of numbers is read.

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     void main( int argc, char **argv )

     {

       read_file( fopen( argv[1], "r" ) );

     }

     void read_file( FILE *input )

     {

       int         line = 0;

       char        buffer[256];

       char        icode;

       char        x, y;

       if( input == NULL ) {

         printf( "Unable to open file\n" );

         return;

       }

       _try {

         for(;;) {

           line++;

           if( fgets( buffer, 255, input ) == NULL ) break;

           icode = buffer[0];

           if( icode != '1' ) return;

           x = buffer[1];

           line++;

           if( fgets( buffer, 255, input ) == NULL ) return;

           icode = buffer[0];

           if( icode != '2' ) return;

           y = buffer[1];

           process( x, y );

         }

         printf( "Processing complete\n" );

         fclose( input );

         input = NULL;

       }

       _finally {

         if( input != NULL ) {

           printf( "Invalid sequence: line = %d\n", line );

           fclose( input );

         }

       }

     }

     void process( char x, char y )

     {

         printf( "processing pair %c,%c\n", x, y );

     }

The above example attempts to read a code and letter.  If an end of file occurs then the loop is terminated by the break statement.

If the code is not 1 then we did not get what we expected and an error condition has arisen.  Control is passed to the first statement in the finally block by the return statement.  An error message is printed and the open file is closed.

If the code is 1 then a second code and number are read.  If an end of file occurs then we are missing a complete set of data and an error condition has arisen.  Control is passed to the first statement in the finally block by the return statement.  An error message is printed and the open file is closed.

Similarly if the expected code is not 2 an error condition has arisen.  The same error handling procedure occurs.

If the second code is 2, the values of variables x and y are processed (printed).  The for loop is repeated again.

The above example illustrates the point that all the information required to test an assumption (that the file contains valid pairs of data) is not available from the start.  We write our code with the assumption that the data values are correct (our hypothesis) and then test the assumption at various points in the algorithm.  If any of the tests fail, we reject the hypothesis.

Consider the following example.  What values are printed by the program?

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     void main( int argc, char **argv )

     {

       int ctr = 0;

       while( ctr < 10 ) {

         printf( "%d\n", ctr );

         _try {

           if( ctr == 2 ) continue;

           if( ctr == 3 ) break;

         }

         _finally {

           ctr++;

         }

         ctr++;

       }

       printf( "%d\n", ctr );

     }

At the top of the loop, the value of ctr is 0.  The next time we reach the top of the loop, the value of ctr is 2 (having been incremented twice, once by the finally block and once at the bottom of the loop).  When ctr has the value 2, the continue statement will cause the finally block to be executed (resulting in ctr being incremented to 3), after which execution continues at the top of the while loop.  When ctr has the value 3, the break statement will cause the finally block to be executed (resulting in ctr being incremented to 4), after which execution continues after the while loop.  Thus the output is:

     0

     2

     3

     4

The point of this exercise was that after the finally block is executed, the normal flow of execution is resumed at the break , continue , return , etc.  statement and the normal behaviour for that statement occurs.  It is as if the compiler had inserted a function call just before the statement that exits the try block.

     _try {

       if( ctr == 2 ) invoke_finally_block() continue;

       if( ctr == 3 ) invoke_finally_block() break;

     }

There is some overhead associated with local unwinds such as that incurred by the use of break , continue , return , etc.  To avoid this overhead, a new transfer keyword called _leave can be used.  The use of this keyword causes a jump to the end of the try block.  Consider the following modified version of an earlier example.

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     void main( int argc, char **argv )

     {

       read_file( fopen( argv[1], "r" ) );

     }

     void read_file( FILE *input )

     {

       int         line = 0;

       char        buffer[256];

       char        icode;

       char        x, y;

       if( input == NULL ) {

         printf( "Unable to open file\n" );

         return;

       }

       _try {

         for(;;) {

           line++;

           if( fgets( buffer, 255, input ) == NULL ) break;

           icode = buffer[0];

           if( icode != '1' ) _leave;

           x = buffer[1];

           line++;

           if( fgets( buffer, 255, input ) == NULL ) _leave;

           icode = buffer[0];

           if( icode != '2' ) _leave;

           y = buffer[1];

           process( x, y );

         }

         printf( "Processing complete\n" );

         fclose( input );

         input = NULL;

       }

       _finally {

         if( input != NULL ) {

           printf( "Invalid sequence: line = %d\n", line );

           fclose( input );

         }

       }

     }

     void process( char x, char y )

     {

       printf( "processing pair %c,%c\n", x, y );

     }

There are two ways to enter the finally block.  One way is caused by unwinds - either local (by the use of break , continue , return , or goto ) or global (more on global unwinds later).  The other way is through the normal flow of execution (i.e., simply by falling through the bottom of the try block).  There is a function called AbnormalTermination that can be used to determine which of these two methods was used to enter the finally block.  If the function returns TRUE (1) then the finally block was entered using the first method; if the function returns FALSE (0) then the finally block was entered using the second method.  This information may be useful in some circumstances.  For example, you may wish to avoid executing any code in a finally block if the block was entered through the normal flow of execution.

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     void main( int argc, char **argv )

     {

       read_file( fopen( argv[1], "r" ) );

     }

     void read_file( FILE *input )

     {

       int         line = 0;

       char        buffer[256];

       char        icode;

       char        x, y;

       if( input == NULL ) {

         printf( "Unable to open file\n" );

         return;

       }

       _try {

         for(;;) {

           line++;

           if( fgets( buffer, 255, input ) == NULL ) break;

           icode = buffer[0];

           if( icode != '1' ) return;

           x = buffer[1];

           line++;

           if( fgets( buffer, 255, input ) == NULL ) return;

           icode = buffer[0];

           if( icode != '2' ) return;

           y = buffer[1];

           process( x, y );

         }

         printf( "Processing complete\n" );

       }

       _finally {

         if( AbnormalTermination() )

             printf( "Invalid sequence: line = %d\n", line );

         fclose( input );

       }

     }

     void process( char x, char y )

     {

       printf( "processing pair %c,%c\n", x, y );

     }

In the above example, we reverted back to the use of the return statement since the execution of a _leave statement is considered part of the normal flow of execution and is not considered an "abnormal termination" of the try block.  Note that since it is not possible to determine whether the finally block is executing as the result of a local or global unwind, it may not be appropriate to use the AbnormalTermination function as a way to determine what has gone on.  However, in our simple example, we expect that nothing could go wrong in the "processing" routine.


Exception Filters and Exception Handlers

We would all like to create flawless software but situations arise for which we did not plan.  An event that we did not expect which causes the software to cease to function properly is called an exception.  The computer can generate a hardware exception when the software attempts to execute an illegal instruction.  We can force this quite easily in C by dereferencing a NULL pointer as shown in the following sample fragment of code.

Example:

         char *nullp = NULL;

         *nullp = '\1';

We can also generate software exceptions from software by calling a special function for this purpose.  We will look at software exceptions in more detail later on.

Given that exceptions are generally very difficult to avoid in large software projects, we can acknowledge that they are a fact of life and prepare for them.  A mechanism similar to try/finally has been devised that makes it possible to gain control when an exception occurs and to execute procedures to handle the situation.

The exception handling mechanism involves the pairing up of a _try block with an _except block.  This is illustrated in the following example.

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     void main( int argc, char **argv )

     {

       char *nullp = NULL;

       printf( "Attempting illegal memory reference.\n" );

       _try {

         *nullp = '\1';

       }

       _except (EXCEPTION_EXECUTE_HANDLER) {

         printf( "Oh no! We had an exception!\n" );

       }

       printf( "We recovered fine...\n" );

     }

In this example, any exception that occurs while executing "inside" the try block will cause the except block to execute.  Unlike the finally block, execution of the except block occurs only when an exception is generated and only when the expression after the _except keyword evaluates to  EXCEPTION_EXECUTE_HANDLER.  The expression can be quite complex and can involve the execution of a function that returns one of the permissible values.  The expression is called the exception "filter" since it determines whether or not the exception is to be handled by the except block.  The permissible result values for the exception filer are:

EXCEPTION_EXECUTE_HANDLER

meaning "I will handle the exception".

EXCEPTION_CONTINUE_EXECUTION

meaning "I want to resume execution at the point where the exception was generated".

EXCEPTION_CONTINUE_SEARCH

meaning "I do not want to handle the exception so continue looking down the try/except chain until you find an exception handler that does want to handle the exception".


Resuming Execution After an Exception

Why would you want to resume execution of the instruction that caused the exception?  Since the exception filter can involve a function call, that function can attempt to correct the problem.  For example, if it is determined that the exception has occurred because of the NULL pointer dereference, the function could modify the pointer so that it is no longer NULL.

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     char *NullP = NULL;

     int filter( void )

     {

       if( NullP == NULL ) {

         NullP = malloc( 20 );

         return( EXCEPTION_CONTINUE_EXECUTION )

       }

       return( EXCEPTION_EXECUTE_HANDLER )

     }

     void main( int argc, char **argv )

     {

       printf( "Attempting illegal memory reference.\n" );

       _try {

         *NullP = '\1';

       }

       _except (filter()) {

         printf( "Oh no! We had an exception!\n" );

       }

       printf( "We recovered fine...\n" );

     }

Unfortunately, this is does not solve the problem.  Understanding why it does not involves looking at the sequence of computer instructions that is generated for the expression in question.

         *NullP = '\1';

             mov     eax,dword ptr _NullP

             mov     byte ptr [eax],01H

The exception is caused by the second instruction which contains a pointer to the referenced memory location (i.e., 0) in register EAX.  This is the instruction that will be repeated when the filter returns EXCEPTION_CONTINUE_EXECUTION.  Since EAX did not get changed by our fix, the exception will reoccur.  Fortunately, NullP is changed and this prevents our program from looping forever.  The moral here is that there are very few instances where you can correct "on the fly" a problem that is causing an exception to occur.  Certainly, any attempt to do so must involve a careful inspection of the computer instruction sequence that is generated by the compiler (and this sequence usually varies with the selection of compiler optimization options).  The best solution is to add some more code to detect the problem before the exception occurs.


Mixing and Matching _try/_finally and _try/_except

Where things really get interesting is in the interaction between try/finally blocks and try/except blocks.  These blocks can be nested within each other.  In an earlier part of the discussion, we talked about global unwinds and how they can be caused by exceptions being generated in nested function calls.  All of this should become clear after studying the following example.

Example:

     #include <stdio.h>

     #include <stdlib.h>

     #include <excpt.h>

     void func_level4( void )

     {

       char *nullp = NULL;

       printf( "Attempting illegal memory reference\n" );

       _try {

         *nullp = '\1';

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level4\n" );

       }

       printf( "Normal return from func_level4\n" );

     }

     void func_level3( void )

     {

       _try {

         func_level4();

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level3\n" );

       }

       printf( "Normal return from func_level3\n" );

     }

     void func_level2( void )

     {

       _try {

         _try {

           func_level3();

         }

         _except (EXCEPTION_CONTINUE_SEARCH) {

           printf( "Exception never handled in func_level2\n" );

         }

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level2\n" );

       }

       printf( "Normal return from func_level2\n" );

     }

     void func_level1( void )

     {

       _try {

         func_level2();

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level1\n" );

       }

       printf( "Normal return from func_level1\n" );

     }

     void func_level0( void )

     {

       _try {

         _try {

           func_level1();

         }

         _except (EXCEPTION_EXECUTE_HANDLER) {

           printf( "Exception handled in func_level0\n" );

         }

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level0\n" );

       }

       printf( "Normal return from func_level0\n" );

     }

     void main( int argc, char **argv )

     {

       _try {

         _try {

           func_level0();

         }

         _except (EXCEPTION_EXECUTE_HANDLER) {

           printf( "Exception handled in main\n" );

         }

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in main\n" );

       }

       printf( "Normal return from main\n" );

     }

In this example,

1.	main calls func_level0

2.	func_level0 calls func_level1

3.	func_level1 calls func_level2

4.	func_level2 calls func_level3

5.	func_level3 calls func_level4

It is in func_level4 where the exception occurs.  The run-time system traps the exception and performs a search of the active try blocks looking for one that is paired up with an except block.

When it finds one, the filter is executed and, if the result is EXCEPTION_EXECUTE_HANDLER, then the except block is executed after performing a global unwind.

If the result is EXCEPTION_CONTINUE_EXECUTION, the run-time system resumes execution at the instruction that caused the exception.

If the result is EXCEPTION_CONTINUE_SEARCH, the run-time system continues its search for an except block with a filter that returns one of the other possible values.  If it does not find any exception handler that is prepared to handle the exception, the application will be terminated with the appropriate exception notification.

Let us look at the result of executing the example program.  The following messages are printed.

     Attempting illegal memory reference

     Unwind in func_level4

     Unwind in func_level3

     Unwind in func_level2

     Unwind in func_level1

     Exception handled in func_level0

     Normal return from func_level0

     Normal return from main

The run-time system searched down the try/except chain until it got to func_level0 which had an except filter that evaluated to EXCEPTION_EXECUTE_HANDLER.  It then performed a global unwind in which the try/finally blocks of func_level4, func_level3, func_level2, and func_level1 were executed.  After this, the exception handler in func_level0 did its thing and execution resumed in func_level0 which returned back to main which returned to the run-time system for normal program termination.  Note the use of the built-in AbnormalTermination function in the finally blocks of each function.

This sequence of events permits each function to do any cleaning up that it deems necessary before it is wiped off the execution stack.


Refining Exception Handling

The decision to handle an exception must be weighed carefully.  It is not necessarily a desirable thing for an exception handler to handle all exceptions.  In the previous example, the expression in the exception filter in func_level0 always evaluates to EXCEPTION_EXECUTE_HANDLER which means it will snag every exception that comes its way.  There may be other exception handlers further on down the chain that are better equipped to handle certain types of exceptions.  There is a way to determine the exact type of exception using the built-in GetExceptionCode() function.  It may be called only from within the exception handler filter expression or within the exception handler block.  Here is a description of the possible return values from the GetExceptionCode() function.

Value

Meaning

EXCEPTION_ACCESS_VIOLATION

The thread tried to read from or write to a virtual address for which it does not have the appropriate access.

EXCEPTION_BREAKPOINT

A breakpoint was encountered.

EXCEPTION_DATATYPE_MISALIGNMENT

The thread tried to read or write data that is misaligned on hardware that does not provide alignment.  For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on.

EXCEPTION_SINGLE_STEP

A trace trap or other single-instruction mechanism signaled that one instruction has been executed.

EXCEPTION_ARRAY_BOUNDS_EXCEEDED

The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking.

EXCEPTION_FLT_DENORMAL_OPERAND

One of the operands in a floating-point operation is denormal.  A denormal value is one that is too small to represent as a standard floating-point value.

EXCEPTION_FLT_DIVIDE_BY_ZERO

The thread tried to divide a floating-point value by a floating-point divisor of zero.

EXCEPTION_FLT_INEXACT_RESULT

The result of a floating-point operation cannot be represented exactly as a decimal fraction.

EXCEPTION_FLT_INVALID_OPERATION

This exception represents any floating-point exception not included in this list.

EXCEPTION_FLT_OVERFLOW

The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.

EXCEPTION_FLT_STACK_CHECK

The stack overflowed or underflowed as the result of a floating-point operation.

EXCEPTION_FLT_UNDERFLOW

The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.

EXCEPTION_INT_DIVIDE_BY_ZERO

The thread tried to divide an integer value by an integer divisor of zero.

EXCEPTION_INT_OVERFLOW

The result of an integer operation caused a carry out of the most significant bit of the result.

EXCEPTION_PRIV_INSTRUCTION

The thread tried to execute an instruction whose operation is not allowed in the current machine mode.

EXCEPTION_NONCONTINUABLE_EXCEPTION

The thread tried to continue execution after a non-continuable exception occurred.

These constants are defined by including WINDOWS.H in the source code.

The following example is a refinement of the func_level1() function in our previous example.

Example:

     #include <windows.h>

     void func_level0( void )

     {

       _try {

         _try {

           func_level1();

         }

         _except (

             (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)

             ? EXCEPTION_EXECUTE_HANDLER

             : EXCEPTION_CONTINUE_SEARCH

             ) {

           printf( "Exception handled in func_level0\n" );

         }

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level0\n" );

       }

       printf( "Normal return from func_level0\n" );

     }

In this version, only an "access violation" will be handled by the exception handler in the func_level0() function.  All other types of exceptions will be passed on to main (which can also be modified to be somewhat more selective about the types of exceptions it should handle).

More information on the exception that has occurred can be obtained by the use of the GetExceptionInformation() function.  The use of this function is also restricted.  It can be called only from within the filter expression of an exception handler.  However, the return value of GetExceptionInformation() can be passed as a parameter to a filter function.  This is illustrated in the following example.

Example:

     int GetCode( LPEXCEPTION_POINTERS exceptptrs )

     {

         return (exceptptrs->ExceptionRecord->ExceptionCode );

     }

     void func_level0( void )

     {

       _try {

         _try {

           func_level1();

         }

         _except (

             (GetCode( GetExceptionInformation() )

                 == EXCEPTION_ACCESS_VIOLATION)

             ? EXCEPTION_EXECUTE_HANDLER

             : EXCEPTION_CONTINUE_SEARCH

             ) {

           printf( "Exception handled in func_level0\n" );

         }

       }

       _finally {

         if( AbnormalTermination() )

           printf( "Unwind in func_level0\n" );

       }

       printf( "Normal return from func_level0\n" );

     }

The return value of GetExceptionInformation() is a pointer to an  EXCEPTION_POINTERS structure that contains pointers to two other structures:  an  EXCEPTION_RECORD structure containing a description of the exception, and a  CONTEXT structure containing the machine-state information.  The filter function can make a copy of the structures if a more permanent copy is desired.  Check your Win32 SDK documentation for more information on these structures.


Throwing Your Own Exceptions

You can use the same exception handling mechanisms to deal with software exceptions raised by your application.  The RaiseException() function can be used to throw your own application-defined exceptions.  The first argument to this function is the exception code.  It would be wise to define your exception codes so that they do not collide with system defined ones.  The following example shows how to throw an exception.

Example:

     #define MY_EXCEPTION ( (DWORD) 123L )

         RaiseException( MY_EXCEPTION,

                         EXCEPTION_NONCONTINUABLE,

                         0, NULL );

In this example, the GetExceptionCode() function, when used in an exception handler filter expression or in the body of an exception handler, would return the value 123.

See the Win32 SDK documentation for more information on the arguments to the RaiseException() function.


Creating ROM-based Applications

This chapter provides information for developers who wish to write applications to be placed in read-only memory (ROM).


ROMable Functions

The following functions in the Open Watcom C/C++ library are not dependent on any operating system.  Therefore they can be used for embedded applications.  The math functions are listed here because they are ROMable, however you must supply a different _matherr function if you are not running in the DOS, OS/2 or Windows NT environment.

abs                 acos                alloca              asctime             asin                atan                atan2               atexit              atof                atoi                atol                bsearch             cabs                ceil                _chain_intr         _clear87            _control87          cos                 cosh                difftime            _disable            div                 _enable             exp                 fabs                floor               _fmemccpy           _fmemchr            _fmemcmp            _fmemcpy            _fmemicmp           _fmemmove           _fmemset            fmod                FP_OFF              FP_SEG              _fpreset            frexp               _fstrcat            _fstrchr            _fstrcmp            _fstrcpy            _fstrcspn           _fstricmp           _fstrlen            _fstrlwr            _fstrncat           _fstrncmp           _fstrncpy           _fstrnicmp          _fstrnset           _fstrpbrk           _fstrrchr           _fstrrev            _fstrset            _fstrspn            _fstrstr            _fstrtok            _fstrupr            gmtime              hypot               inp                 inpw                int86 (1)           int86x (1)          int386 (2)          int386x (2)         intr                isalnum             isalpha             isascii             iscntrl             isdigit             isgraph             islower             isprint             ispunct             isspace             isupper             isxdigit            itoa                j0                  j1                  jn                  labs                ldexp               ldiv                lfind               localeconv          log                 log10               longjmp             _lrotl              _lrotr              lsearch             ltoa                matherr             mblen               mbstowcs            mbtowc

memccpy             memchr              memcmp              memcpy              memicmp             memmove             memset              MK_FP               modf                movedata            offsetof            outp                outpw               pow                 qsort               rand                _rotl               _rotr               segread             setjmp              setlocale           sin                 sinh                sprintf             sqrt                srand               sscanf              stackavail          _status87           strcat              strchr              strcmp              strcmpi             strcoll             strcpy              strcspn             strdup              strerror            stricmp             strlen              strlwr              strncat             strncmp             strncpy             strnicmp            strnset             strpbrk             strrchr             strrev              strset              strspn              strstr              strtod              strtok              strtol              strtoul             strupr              strxfrm             swab                tan                 tanh                tolower             toupper             ultoa               utoa                va_arg              va_end              va_start            vsprintf            vsscanf             wcstombs            wctomb              y0                  y1                  yn

     * (1) 16-bit libraries

     * (2) 32-bit libraries


System-Dependent Functions

The following functions in the C/C++ library directly or indirectly make use of operating system functions.  They cannot be used on systems that are not running on one of the DOS, OS/2 or Windows NT operating systems.

abort               access              assert              bdos                _beginthread        _bios_disk          _bios_equiplist     _bios_keybrd        _bios_memsize       _bios_printer       _bios_serialcom     _bios_timeofday     calloc              cgets               chdir               chmod               chsize              clearerr            clock               close               closedir            cprintf             cputs               creat               cscanf              ctime               cwait               delay               _dos_allocmem       _dos_close          _dos_creat          _dos_creatnew       _dos_findfirst      _dos_findnext       _dos_freemem        _dos_getdate        _dos_getdiskfree    _dos_getdrive       _dos_getfileattr    _dos_getftime       _dos_gettime        _dos_getvect        _dos_keep           _dos_open           _dos_read           _dos_setblock       _dos_setdate        _dos_setdrive       _dos_setfileattr    _dos_setftime       _dos_settime        _dos_setvect        _dos_write          dosexterr           dup                 dup2                _endthread          eof                 execl (1)           execle (1)          execlp (1)          execlpe (1)         execv (1)           execve (1)          execvp (1)          execvpe (1)         exit                _exit               fclose              fcloseall           fdopen              feof                ferror              fflush              _ffree              _fheapchk           _fheapgrow (1)      _fheapmin           _fheapset           _fheapshrink        _fheapwalk          fgetc               fgetpos             fgets               filelength          fileno              flushall            _fmalloc            fopen               fprintf             fputc               fputs               fread               _frealloc           free                freopen             fscanf              fseek               fsetpos             fstat

ftell               fwrite              getc                getch               getchar             getche              getcmd              getcwd              getenv              getpid              gets                halloc              _heapchk            _heapgrow           _heapmin            _heapset            _heapshrink         _heapwalk           hfree               intdos              intdosx             isatty              kbhit               localtime           lock                locking             lseek               _makepath           malloc              mkdir               mktime              _nfree              _nheapchk           _nheapgrow          _nheapmin           _nheapset           _nheapshrink        _nheapwalk          _nmalloc            _nrealloc           nosound             open                opendir             perror              printf              putc                putch               putchar             putenv              puts                raise               read                readdir             realloc             remove              rename              rewind              rmdir               sbrk                scanf               _searchenv          setbuf              setmode             setvbuf             signal              sleep               sopen               sound               spawnl              spawnle             spawnlp             spawnlpe            spawnv              spawnve             spawnvp             spawnvpe            _splitpath          stat                strftime            system              tell                time                tmpfile             tmpnam              tzset               umask               ungetc              ungetch             unlink              unlock              utime               vfprintf            vfscanf             vprintf             vscanf              wait                write

     * (1) 16-bit libraries


Modifying the Startup Code

Source files are included in the package for the Open Watcom C/C++ application start-up (or initialization) sequence.  These files are described in the section entitled The Open Watcom C/C++ Run-time Initialization Routines.  The startup code will have to be modified if you are creating a ROMable application or you are not running in a DOS, OS/2, QNX, or Windows environment.


Choosing the Correct Floating-Point Option

If there will be a math coprocessor chip in your embedded system, then you should compile your application with the "fpi87" option and one of "fp2", "fp3" or "fp5" depending on which math coprocessor chip will be in your embedded system.  If there will not be a math coprocessor chip in your embedded system, then you should compile your application with the "fpc" option.  You should not use the "fpi" option since that will cause extra code to be linked into your application to decode and emulate the 80x87 instructions contained in your application.


Use of Environment Variables

In the Open Watcom C/C++ software development package, a number of environment variables are used.  This appendix summarizes their use with a particular component of the package.


FORCE

The FORCE environment variable identifies a file that is to be included as part of the source input stream.  This variable is used by Open Watcom C/C++.

     SET FORCE=[d:][path]filename[.ext]

The specified file is included as if a

     #include "[d:][path]filename[.ext]"

directive were placed at the start of the source file.

Example:

     C>set force=\watcom\h\common.cnv

     C>wcc report

The FORCE environment variable can be overridden by use of the Open Watcom C/C++ "fi" option.


INCLUDE

The INCLUDE environment variable describes the location of the C and C++ header files (files with the ".h" filename extension).  This variable is used by Open Watcom C/C++.

     SET include=[d:][path];[d:][path]...

The INCLUDE environment string is like the PATH string in that you can specify one or more directories separated by semicolons (";").


LFN

The LFN environment variable is checked by the Open Watcom run-time C libraries and it is used to control DOS LFN (DOS Long File Name) support.  Normally, these libraries will use DOS LFN support if it is available on host OS.  If you don't wish to use DOS LFN support, you can define the LFN environment variable and setup it's value to 'N'.  Using the "SET" command, define the environment variable as follows:

     SET LFN=N

Now, when you run your application, the DOS LFN support will be ignored.  To undefine the environment variable, enter the command:

     SET LFN=


LIB

The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended over the use of this environment variable.

The LIB environment variable is used to select the libraries that will be used when the application is linked.  This variable is used by the Open Watcom Linker (WLINK.EXE).  The LIB environment string is like the PATH string in that you can specify one or more directories separated by semicolons (";").

If you have the 286 development system, 16-bit applications can be linked for DOS, Microsoft Windows, OS/2, and QNX depending on which libraries are selected.  If you have the 386 development system, 32-bit applications can be linked for DOS Extender systems, Microsoft Windows and QNX.


LIBDOS

The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended over the use of this environment variable.

If you are developing a DOS application, the LIBDOS environment variable must include the location of the 16-bit Open Watcom C/C++ DOS library files (files with the ".lib" filename extension).  This variable is used by the Open Watcom Linker (WLINK.EXE).  The default installation directory for the 16-bit Open Watcom C/C++ DOS libraries is \WATCOM\LIB286\DOS.  The LIBDOS environment variable must also include the location of the 16-bit Open Watcom C/C++ math library files.  The default installation directory for the 16-bit Open Watcom C/C++ math libraries is \WATCOM\LIB286.

Example:

     C>set libdos=c:\watcom\lib286\dos;c:\watcom\lib286


LIBWIN

The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended over the use of this environment variable.

If you are developing a 16-bit Microsoft Windows application, the LIBWIN environment variable must include the location of the 16-bit Open Watcom C/C++ Windows library files (files with the ".lib" filename extension).  This variable is used by the Open Watcom Linker (WLINK.EXE).  If you are developing a 32-bit Microsoft Windows application, see the description of the LIBPHAR environment variable.  The default installation directory for the 16-bit Open Watcom C/C++ Windows libraries is \WATCOM\LIB286\WIN.  The LIBWIN environment variable must also include the location of the 16-bit Open Watcom C/C++ math library files.  The default installation directory for the 16-bit Open Watcom C/C++ math libraries is \WATCOM\LIB286.

Example:

     C>set libwin=c:\watcom\lib286\win;c:\watcom\lib286


LIBOS2

The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended over the use of this environment variable.

If you are developing an OS/2 application, the LIBOS2 environment variable must include the location of the 16-bit Open Watcom C/C++ OS/2 library files (files with the ".lib" filename extension).  This variable is used by the Open Watcom Linker (WLINK.EXE).  The default installation directory for the 16-bit Open Watcom C/C++ OS/2 libraries is \WATCOM\LIB286\OS2.  The LIBOS2 environment variable must also include the directory of the OS/2 DOSCALLS.LIB file which is usually \OS2.  The LIBOS2 environment variable must also include the location of the 16-bit Open Watcom C/C++ math library files.  The default installation directory for the 16-bit Open Watcom C/C++ math libraries is \WATCOM\LIB286.

Example:

     C>set libos2=c:\watcom\lib286\os2;c:\watcom\lib286;c:\os2


LIBPHAR

The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended over the use of this environment variable.

If you are developing a 32-bit Windows or DOS Extender application, the LIBPHAR environment variable must include the location of the 32-bit Open Watcom C/C++ DOS Extender library files or the 32-bit Open Watcom C/C++ Windows library files (files with the ".lib" filename extension).  This variable is used by the Open Watcom Linker (WLINK.EXE).  The default installation directory for the 32-bit Open Watcom C/C++ DOS Extender libraries is \WATCOM\LIB386\DOS.  The default installation directory for the 32-bit Open Watcom C/C++ Windows libraries is \WATCOM\LIB386\WIN.  The LIBPHAR environment variable must also include the location of the 32-bit Open Watcom C/C++ math library files.  The default installation directory for the 32-bit Open Watcom C/C++ math libraries is \WATCOM\LIB386.

Example:

     C>set libphar=c:\watcom\lib386\dos;c:\watcom\lib386

         or

     C>set libphar=c:\watcom\lib386\win;c:\watcom\lib386


NO87

The NO87 environment variable is checked by the Open Watcom run-time math libraries that include floating-point emulation support.  Normally, these libraries will detect the presence of a numeric data processor (80x87) and use it.  If you have a numeric data processor in your system but you wish to test a version of your application that will use floating-point emulation, you can define the NO87 environment variable.  Using the "SET" command, define the environment variable as follows:

     SET NO87=1

Now, when you run your application, the 80x87 will be ignored.  To undefine the environment variable, enter the command:

     SET NO87=


PATH

The PATH environment variable is used by DOS "COMMAND.COM" or OS/2 "CMD.EXE" to locate programs.

     PATH [d:][path];[d:][path]...

The PATH environment variable should include the disk and directory of the Open Watcom C/C++ binary program files when using Open Watcom C/C++ and its related tools.

If your host system is DOS:

The default installation directory for 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ DOS binaries is called \WATCOM\BINW.

Example:

     C>path c:\watcom\binw;c:\dos;c:\windows

If your host system is OS/2:

The default installation directories for 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ OS/2 binaries are called \WATCOM\BINP and \WATCOM\BINW.

Example:

     [C:\]path c:\watcom\binp;c:\watcom\binw

If your host system is Windows NT:

The default installation directories for 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ Windows NT binaries are called \WATCOM\BINNT and \WATCOM\BINW.

Example:

     C>path c:\watcom\binnt;c:\watcom\binw

The PATH environment variable is also used by the following programs in the described manner.

1.	Open Watcom Compile and Link to locate the 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ compilers and the Open Watcom Linker.

2.	"WD.EXE" to locate programs and debugger command files.


TMP

The TMP environment variable describes the location (disk and path) for temporary files created by the 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ compilers and the Open Watcom Linker.

     SET TMP=[d:][path]

Normally, Open Watcom C/C++ will create temporary spill files in the current directory.  However, by defining the TMP environment variable to be a certain disk and directory, you can tell Open Watcom C/C++ where to place its temporary files.  The same is true of the Open Watcom Linker temporary file.

Consider the following definition of the TMP environment variable.

Example:

     C>set tmp=d:\watcom\tmp

The Open Watcom C/C++ compiler and Open Watcom Linker will create its temporary files in d:\watcom\tmp.


WATCOM

In order for the Open Watcom Linker to locate the 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ library files, the WATCOM environment variable should be defined.  The WATCOM environment variable is used to locate the libraries that will be used when the application is linked.  The default directory for 16-bit Open Watcom C/C++ and 32-bit Open Watcom C/C++ files is "\WATCOM".

Example:

     C>set watcom=c:\watcom


WCC

The WCC environment variable can be used to specify commonly-used options for the 16-bit C compiler.

     SET WCC=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "d1" (include line number debug information in the object file) and "ox" (compile for maximum number of code optimizations).

Example:

     C>set wcc=/d1 /ox

Once the WCC environment variable has been defined, those options listed become the default each time the WCC command is used.


WCC386

The WCC386 environment variable can be used to specify commonly-used options for the 32-bit C compiler.

     SET WCC386=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "d1" (include line number debug information in the object file) and "ox" (compile for maximum number of code optimizations).

Example:

     C>set wcc386=/d1 /ox

Once the WCC386 environment variable has been defined, those options listed become the default each time the WCC386 command is used.


WCL

The WCL environment variable can be used to specify commonly-used WCL options.

     SET WCL=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "mm" (compile code for medium memory model), "d1" (include line number debug information in the object file), and "ox" (compile for maximum number of code optimizations).

Example:

     C>set wcl=/mm /d1 /ox

Once the WCL environment variable has been defined, those options listed become the default each time the WCL command is used.


WCL386

The WCL386 environment variable can be used to specify commonly-used WCL386 options.

     SET WCL386=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "3s" (compile code for stack-based argument passing convention), "d1" (include line number debug information in the object file), and "ox" (compile for maximum number of code optimizations).

Example:

     C>set wcl386=/3s /d1 /ox

Once the WCL386 environment variable has been defined, those options listed become the default each time the WCL386 command is used.


WCGMEMORY

The WCGMEMORY environment variable may be used to request a report of the amount of memory used by the compiler's code generator for its work area.

Example:

     C>set WCGMEMORY=?

When the memory amount is "?" then the code generator will report how much memory was used to generate the code.

It may also be used to instruct the compiler's code generator to allocate a fixed amount of memory for a work area.

Example:

     C>set WCGMEMORY=128

When the memory amount is "nnn" then exactly "nnnK" bytes will be used.  In the above example, 128K bytes is requested.  If less than "nnnK" is available then the compiler will quit with a fatal error message.  If more than "nnnK" is available then only "nnnK" will be used.

There are two reasons why this second feature may be quite useful.  In general, the more memory available to the code generator, the more optimal code it will generate.  Thus, for two personal computers with different amounts of memory, the code generator may produce different (although correct) object code.  If you have a software quality assurance requirement that the same results (i.e., code) be produced on two different machines then you should use this feature.  To generate identical code on two personal computers with different memory configurations, you must ensure that the WCGMEMORY environment variable is set identically on both machines.

The second reason where this feature is useful is on virtual memory paging systems (e.g., OS/2) where an unlimited amount of memory can be used by the code generator.  If a very large module is being compiled, it may take a very long time to compile it.  The code generator will continue to allocate more and more memory and cause an excessive amount of paging.  By restricting the amount of memory that the code generator can use, you can reduce the amount of time required to compile a routine.


WD

The WD environment variable can be used to specify commonly-used Open Watcom Debugger options.  This environment variable is not used by the Windows version of the debugger, WDW.

     SET WD=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "noinvoke" (do not execute the profile.dbg file) and "reg=10" (retain up to 10 register sets while tracing).

Example:

     C>set wd=/noinvoke /reg#10

Once the WD environment variable has been defined, those options listed become the default each time the WD command is used.


WDW

The WDW environment variable can be used to specify commonly-used Open Watcom Debugger options.  This environment variable is used by the Windows version of the debugger, WDW.

     SET WDW=/option1 /option2 ...

These options are processed before options specified in the WDW prompt dialogue box.  The following example defines the default options to be "noinvoke" (do not execute the profile.dbg file) and "reg=10" (retain up to 10 register sets while tracing).

Example:

     C>set wdw=/noinvoke /reg#10

Once the WDW environment variable has been defined, those options listed become the default each time the WDW command is used.


WLANG

The WLANG environment variable can be used to control which language is used to display diagnostic and program usage messages by various Open Watcom software tools.  The two currently-supported values for this variable are "English" or "Japanese".

     SET WLANG=English

     SET WLANG=Japanese

Alternatively, a numeric value of 0 (for English) or 1 (for Japanese) can be specified.

Example:

     C>set wlang=0

By default, Japanese messages are displayed when the current codepage is 932 and English messages are displayed otherwise.  Normally, use of the WLANG environment variable should not be required.


WPP

The WPP environment variable can be used to specify commonly-used options for the 16-bit C++ compiler.

     SET WPP=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "d1" (include line number debug information in the object file) and "ox" (compile for maximum number of code optimizations).

Example:

     C>set wpp=/d1 /ox

Once the WPP environment variable has been defined, those options listed become the default each time the WPP command is used.


WPP386

The WPP386 environment variable can be used to specify commonly-used options for the 32-bit C++ compiler.

     SET WPP386=/option1 /option2 ...

These options are processed before options specified on the command line.  The following example defines the default options to be "d1" (include line number debug information in the object file) and "ox" (compile for maximum number of code optimizations).

Example:

     C>set wpp386=/d1 /ox

Once the WPP386 environment variable has been defined, those options listed become the default each time the WPP386 command is used.


Open Watcom C/C++ Run-Time Messages

The following is a list of error messages produced by the Open Watcom C/C++ run-time library.  These messages can only appear during the execution of an application built with one of the C run-time libraries.


Run-Time Error Messages

Assertion failed:  %s, file %s, line %d

This message is displayed whenever an assertion that you have made in your program is not true.

Stack Overflow!

Your program is trying to use more stack space than is available.  If you believe that your program is correct, you can increase the size of the stack by using the "option stack=nnnn" when you link the program.  The stack size can also be specified with the "k" option if you are using WCL or WCL386.

Floating-point support not loaded

You have called one of the printf functions with a format of "%e", "%f", or "%g", but have not passed a floating-point value.  The compiler generates a reference to the variable "_fltused_" whenever you pass a floating-point value to a function.  During the linking phase, the extra floating-point formatting routines will also be brought into your application when "_fltused_" is referenced.  Otherwise, you only get the non floating-point formatting routines.

*** NULL assignment detected

This message is displayed if any of the first 32 bytes of your program's data segment has been modified.  The check is performed just before your program exits to the operating system.  All this message means is that sometime during the execution of your program, this memory was modified.

To find the problem, you must link your application with debugging information and use Open Watcom Debugger to monitor its execution.  First, run the application with Open Watcom Debugger until it completes.  Examine the first 16 bytes of the data segment ("examine __nullarea") and press the space bar to see the next 16 bytes.  Any values that are not equal to '01' have been modified.  Reload the application, set watch points on the modified locations, and start execution.  Open Watcom Debugger will stop when the specified location(s) change in value.


errno Values and Their Meanings

The following errors can be generated by the C run-time library.  These error codes correspond to the error types defined in errno.h.

ENOENT

 No such file or directory

The specified file or directory cannot be found.

E2BIG

 Argument list too big

The argument list passed to the spawn..., exec...  or system functions requires more than 128 bytes, or the environment information exceeds 32K.

ENOEXEC

 Exec format error

The executable file has an invalid format.

EBADF

 Bad file number

The file handle is not a valid file handle value or it does not correspond to an open file.

ENOMEM

 Not enough memory

There was not enough memory available to perform the specified request.

EACCES

 Permission denied

You do not have the required (or correct) permissions to access a file.

EEXIST

 File exists

An attempt was made to create a file with the O_EXCL (exclusive) flag when the file already exists.

EXDEV

 Cross-device link

An attempt was made to rename a file to a different device.

EINVAL

 Invalid argument

An invalid value was specified for one of the arguments to a function.

ENFILE

 File table overflow

All the FILE structures are in use, so no more files can be opened.

EMFILE

 Too many open files

There are no more file handles available, so no more files can be opened.  The maximum number of file handles available is controlled by the "FILES=" option in the "CONFIG.SYS" file.

ENOSPC

 No space left on device

No more space is left for writing on the device, which usually means that the disk is full.

EDOM

 Argument too large

An argument to a math function is not in the domain of the function.

ERANGE

 Result too large

The result of a math function could not be represented (too small, or too large).

EDEADLK

 Resource deadlock would occur

A resource deadlock would occur with regards to locked files.


Math Run-Time Error Messages

The following errors can be generated by the math functions in the C run-time library.  These error codes correspond to the exception types defined in math.h and returned by the matherr function when a math error occurs.

DOMAIN

 Domain error

An argument to the function is outside the domain of the function.

OVERFLOW

 Overflow range error

The function result is too large.

PLOSS

 Partial loss of significance

A partial loss of significance occurred.

SING

 Argument singularity

An argument to the function has a bad value (e.g., log(0.0)).

TLOSS

 Total loss of significance

A total loss of significance occurred.  An argument to a function was too large to produce a meaningful result.

UNDERFLOW

 Underflow range error

The result is too small to be represented.