Copyright © 2002 Southern Storm Software, Pty Ltd.
Permission to distribute copies of this work under the terms of the
GNU Free Documentation License is hereby granted.
We assume that the user has already installed all of the Portable.NET components, including the compiler and C system library.
Note: This is preliminary documentation. Not all listed features may be implemented yet. In particular, we do not yet have an implementation of "libc", so the "printf" examples will not work.
To compile and run this with Portable.NET, use the following commands:#include <stdio.h> int main(int argc, char *argv[]) { printf("Hello World!\n"); return 0; }
As can be seen, this is very similar to using a traditional C compiler. Just use the "$ cscc -o hello.exe hello.c $ ilrun hello.exe Hello World! $ _
cscc
" command instead of "gcc
"
or "cc
".Now let's try something a little more complicated:
Compiling and running this gives the following result:#include <stdio.h> int main(int argc, char *argv[]) { printf("sizeof(int) = %u\n", sizeof(int)); printf("sizeof(void *) = %u\n", sizeof(void *)); return 0; }
If you were running this on a 32-bit operating system, this output might seem a little puzzling. Normally, "$ cscc -o sizes.exe sizes.c $ ilrun sizes.exe sizeof(int) = 4 sizeof(void *) = 8 $ _
sizeof(void *)
"
will be 8 bytes on a 64-bit operating system, not a 32-bit one.
Why isn't the value 4 instead?The output of the C compiler is designed to run on a Common Language Runtime (CLR) implementation, not on a native operating system. When we compile the program, the compiler does not know what kind of CLR will be used to execute it.
The compiler builds the program as though it will be running on a 64-bit CLR. If the program is subsequently executed on a 32-bit CLR, the program will function correctly, and pretend that it is operating in a 64-bit environment. This way, the compiler does not need to know the actual characteristics of the CLR.
Sometimes you may want to force the compiler to output 32-bit code, or code that is tuned for the specifics of a particular platform. If you do this, then the program will not execute on CLR's that have different characteristics. i.e. it will no longer be portable.
The following two examples demonstrate how to build 32-bit programs, and programs that use the native type layout policy:
If you want your program to be portable to many operating systems, you should not use these options when compiling.$ cscc -m32bit-only -o sizes.exe sizes.c $ cscc -mnative-types -o sizes.exe sizes.c
Type | Size | Description |
void |
1 1 | Void type |
__bool__ |
1 | 8-bit boolean value (C# "bool ") |
char |
1 | Signed 8-bit integer |
unsigned char |
1 | Unsigned 8-bit integer |
short |
2 | Signed 16-bit integer |
unsigned short |
2 | Unsigned 16-bit |
__wchar__ |
2 | 16-bit wide character value (C# "char ") |
int |
4 | Signed 32-bit integer |
unsigned int |
4 | Unsigned 32-bit integer |
long |
4/8 2 | Signed 32-bit or 64-bit integer |
unsigned long |
4/8 2 | Unsigned 32-bit or 64-bit integer |
long long |
8 | Signed 64-bit integer |
unsigned long long |
8 | Unsigned 64-bit integer |
__native__ int |
? 3 | Signed native integer |
unsigned __native__ int |
? 3 | Unsigned native integer |
float |
4 | 32-bit IEEE 754 floating-point |
double |
8 | 64-bit IEEE 754 floating-point |
long double |
? 3 | Native floating-point |
type * |
4/8 2 | Pointer to "type " |
Note 1. The size of "void
" is 1, to be
consistent with gcc.
Note 2. These types are 4 bytes in size if "-m32bit-only
"
was specified at compile time, and 8 bytes in size otherwise.
Note 3. The size of these types is determined at runtime, based on
the corresponding types in the runtime engine.
struct
" and
"union
" types to simulate the behaviour of a 64-bit
operating system. The "-m32bit-only
" option can be
used to specific 32-bit layout instead.
However, sometimes you need to access features of the native operating
system, even if writing a portable 64-bit application. When you do,
you need to guarantee that "struct
" and "union
"
types exactly match what the operating system expects.
Native structures can be defined by adding the "__native__
"
keyword to their declaration:
In this structure, the "struct __native__ A { int item; struct A *next; };
next
" field is guaranteed to
occupy only enough space for a native pointer, and to be aligned on
an appropriate native word boundary. If the "__native__
"
keyword was not present, the "next
" field would always
occupy a full 8 bytes, even if the CLR was only using 4-byte pointers
behind the scenes.
If you use the "-mnative-types
" command-line option, then
all structures will be laid out using the native policy, and there is
no need to use the "__native__
" keyword. But the resulting
program will only work on the system for which it was compiled.
It probably won't work on any other system.
Unions may also have the "__native__
" keyword:
union __native__ A { int x; void *y; };
setjmp
and alloca
setjmp
"
and "alloca
" constructs must be used carefully. In particular,
they must be used at the "statement level" of an expression.The following code is correct:
But the following code will give an error when compiled:jmp_buf env; if(setjmp(env) != 0) { /* longjmp occurred */ }
This is because the "jmp_buf env; if((1 + setjmp(env)) != 1) { /* longjmp occurred */ }
setjmp
" does not occur at the outermost
level of the expression (the value 1 is stored on the stack temporarily,
pending the addition operation). The "alloca
" construct must be
used in a similar manner.If you get such an error, you can split your code up a little bit. For example:
The variable that you assign to will normally need to be a local variable, global variable, or parameter. Other kinds of variables (e.g. array elements) will change the expression level and so cannot be used.jmp_buf env; int result; result = setjmp(env); if((1 + result) != 1) { /* longjmp occurred */ }
This restriction is imposed by the way that CLR's implement
"setjmp
" and "alloca
". Most C programmers
already use these constructs at the statement level of an expression,
so this restriction is not expected to affect much existing code.