How to convert C/C++ code to lite-C
Lite-C supports a syntax subset of the C/C++ language. In
most cases - when no particular C++ features, like STL, are used -
a C/C++ programm can be easily converted to lite-C. Examples
for this are the DirectX samples that come with the lite-C installation; they
are just slightly modified versions of the original samples from the DirectX
9 SDK. For converting a C/C++ program to lite-C, the following modifications
are required:
Trinary operators
Lite-C does not support the comparison ? expression : expression; syntax,
so an if statement must be used:
x = (x<0 ? -1 : 1); // C/C++
if (x<0) x=-1; else x=1; // lite-C
Struct and array initialization
In C/C++ arrays structs can be initialized by giving a list of member values,
like VECTOR
myvector = { 0,0,0 };. This is only supported for global structs and arrays
in lite-C. Local structs can not be initialized, and local initialized arrays
automatically become static.
Lite-C initializes all global arrays and structs automatically to zero; local
arrays and structs are normally not initialized and thus contain random content.
Thus, use the zero() macro
(defined in acknex.h) for initalizing local structs to zero, and vec_zero() for
initializing vectors consisting of 3 vars:
VECTOR speed;
...
vec_zero(speed); // initializes the VECTOR "speed" to x=0,y=0,z=0
For migration and testing, lite-C can automatically initialize also all
local variables to zero with the PRAGMA_ZERO definition. If you
add
#define PRAGMA_ZERO // initialize variables
at the beginning of your script, all uninitialized local variables and
structs are set to zero. This slows down function calls a little, so it's
preferable not to to use PRAGMA_ZERO in your final version.
Enums
Enums can be replaced by defines:
enum RGB { RED=1; BLUE=2; GREEN=3 }; // C/C++
#define RED 1 // lite-C
#define BLUE 2
#define GREEN 3
Unions
Union members of the same type can be substituted
by a #define, and union members of different type can be treated as a
different members of the struct. Example:
typedef struct S_UNION {
int data1;
union { int data2; float data3; };
union { int data4; int data5; };
} S_UNION; // C/C++
typedef struct S_UNION {
int data1;
int data2;
float data3;
int data4;
} S_UNION; // lite-C
#define data5 data4
If the struct size must not change, or if for some reason the program requires
different variable types to occupy the same place in the struct, a special
conversion function can be used to convert the type of a variable without converting
the content:
typedef struct S_UNION {
int data1;
union { int data2; float data3; };
} S_UNION; // C/C++
...
S_UNION s_union;
s_union.data3 = 3.14;
typedef struct S_UNION {
int data1;
int data2;
} S_UNION; // lite-C
#define data3 data2
...
int union_int_float(float x) { return *((int*)&x); }
...
S_UNION s_union;
s_union.data3 = union_int_float(3.14);
Function pointers
In C/C++, function pointers are declared like this: int (*foo)(int
a, int b);.
In lite-C there's no difference between function prototypes and
function pointers: int foo(int a, int b);. See details under pointers.
Signed or unsigned variables
In lite-C, floating point, long and int variables are generally signed, and pointers,
char and short are generally unsigned, according to the normal way they are used.
The
include\litec.h file
contains definitions for all usual unsigned variables like DWORD or WORD that
are used in Windows functions. So using unsigned variables normally does not
cause any problems. However you need to take care when variables exceed
their range. For instance, subtracting 1 from (DWORD)0 results
in -1 under lite-C, but in 0xFFFFFFFF in standard C/C++, and would
produce different behavior in comparisons.
Adding C library functions
Lite-C contains only a subset of all functions from the standard C/C++ libraries,
but you can add any function that you need as described under Using
the Windows API. Here's a brief instruction of how to add a API function
to lite-C:
- Find out in which Windows DLL the function is contained. C library function
are normally found in the mscvrt.dll. You can use a free DLL browser,
for instance the DLL Export Viewer from http://www.nirsoft.net,
for checking which DLL contains which function.
- Declare a function prototype in your source code. In most cases you can
directly copy the prototype from the .h header file that accompanies
the DLL, or from the documentation to the C library.
- Additionally to the prototype, either add a #define PRAGMA_API line
for initializing the function prototype, f.i. #define PRAGMA_API MessageBox;user32!MessageBoxA as
described in the API example. Or, for dynamic initalization, add a DefineApi call
in your main function.
If you need certain structs or variable types that are not yet contained in include\windows.h or
in the other standard include files, just add them from their original file
either into your script. If you think that a certain function, struct, or variable
type is often needed, suggest its inclusion into api.def on the Gamestudio
future forum rather than modifying api.def yourself. Self-modified files
are overwritten by lite-C updates.
Adding DirectX API functions
DirectX and other Windows SDKs use the Component Object Model (COM) as described
in the API chapter. For convenience, the Windows
interface definitions (like DECLARE_INTERFACE_ and STDMETHOD_)
are already contained in the lite-C include\d3d9.h file, and the basic
classes are already defined within. So it'is easy to add further interface classes
when they are needed. Just copy the class definition from the original d3d9.h or
other DirectX header file into it's lite-C counterpart, and add the inherited
methods (if any) from the parent class.
Compiling a lite-C script with other C++ compilers
As long as you don't use any special lite-C syntax, like global struct
initialization or pointer autodetection, you can normally compile a lite-C
legacy mode script with any other C++ compiler. Here's an example how to
compile the mandelbrot_legacy.c file with Visual Studio 2003:
- Start VC++ 2003. First you need to create an empty project. Select File
/ New / Project / Win32 Project. In the field below enter the project
name, like "Mandelbrot_Legacy", then click OK.
In the following dialog check Empty Project under Application
Settings, then
click Finish. VC++ will now create a project for you.
- Copy mandelbrot_legacy.c
into the project folder that VC++ has created, and rename it to .cpp (you're
using classes, so it's a C++ program). Add it to the project: In the VC++
Solution explorer, right click on Source
Files, and select Add / Add Existing Item / mandelbrot_legacy.cpp. That
should be the only file of the project.
- Because VC++ does not know about your
lite-C includes, you need to give the path to the litec.h file.
Edit the "#include <litec.h>" line,
and enter the path to litec.h in double quotes, like #include "C:\program
files\litec\include\litec.h".
- Compile it with
Build \ Build Solution, then run it with Debug
\ Start.
See also:
Pointers, Structs, Functions, Windows
API