65.9K
CodeProject 正在变化。 阅读更多。
Home

将 C 代码编译为 .NET - 第一部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (75投票s)

2016 年 9 月 13 日

CPOL

7分钟阅读

viewsIcon

155150

downloadIcon

1708

借助这款新的 OrangeC/C++ 编译器后端,您可以将 C 代码编译为 .NET。

引言

许多以 C 语言编程并开始学习 C# / VB 或其他 .NET 编译语言的开发者,常常希望甚至需要调用他们用 C 语言编写的函数代码。

每当我上网搜索,或者谈论使用 Visual C++ 和编译器中的 /clr 选项,或使用 pInvoke 来调用 C 函数时。

于是,我和我的朋友 David(OrangeC/C++ 编译器的创建者)聊天时,我给了他一个想法:为他的编译器创建一个新的后端,该后端可以生成 CLR 代码。因此,当时并没有一个开源的 C 语言编译器可以生成 CLR 代码。

在分离了生成 x86 代码的编译器后端后,经过一系列修复和实现,新后端的开发工作得以启动。我们成功地编译了 Sqlite3,并使用 C# 代码编译的 DLL。

关于 OrangeC 至 .NET 的文章

C/C++ 编译器和 MSIL 后端的链接

您可以通过以下链接关注 OrangeC/C++ 编译器的开发或为该项目做出贡献。

构建 Orangec 编译器和 Orangec for Msil

要构建 Orange C 编译器(MSIL 版本),您需要下载 OrangeC 编译器的完整代码。您可以在以下位置获取源代码:

要构建源代码,需要安装以下编译器之一:

  • MinGW
  • CLang
  • Visual C/C++ 15
  • OrangeC 编译器

下载并解压所有文件后,打开 CMD,导航到 C:\orangec\src 文件夹,输入 config.bat。执行完 config.bat 后,输入:

  • omake fullbuild

这将构建整个 orangec 编译器。

执行完这些命令后,您将得到 occil.exe

使用 OrangeC 编译器生成 .NET 可执行文件

要使用该编译器,只需在本文提供的链接中下载,将所有 zip 内容解压到 C:\ 文件夹,打开 CMD 并导航到 C:\OrangeC 文件夹。进入 occil 文件夹后,键入 config.bat。运行 config.bat 文件时,将在您的 CMD 上下文中创建一个新的环境变量,以便编译器能够找到 include 文件夹和其他库。

让我们创建一个简单的示例

创建一个名为 "float_to_ieee754.c" 的 C 文件,并将以下代码放入您的 C 文件中:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *strrev_t(char *str)
{
    char *p1, *p2;

    if (!str || !*str)
        return str;
    for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
    {
        *p1 ^= *p2;
        *p2 ^= *p1;
        *p1 ^= *p2;
    }
    return str;
}

void floatToBinary(float f, char *str, int numeroDeBits)
{
    int i = 0;
    int strIndex = 0;
    union
    {
        float f;
        unsigned int i;
    }u;
    u.f = f;
    memset(str, '0', numeroDeBits);

    for (i = 0; i < numeroDeBits; i++)
    {
        str[strIndex++] = (u.i & (1 << 0)) ? '1' : '0';
        u.i >>= 1;
    }

      str[strIndex] = '\0';
 
    str = strrev_t(str);
}

int main()
{
    float input = 0.0;
    const int numeroDeBits = 32;
    char *str = (char*)malloc(sizeof(char) * numeroDeBits);
    printf("Type a float number to convert to binary: ");
    scanf("%f", &input);
    floatToBinary(input, str, numeroDeBits);
    printf("%s\n", str);
    if(str != NULL)
    free(str);     
    return 0;
}

附注:需要将以下 DLL 从 bin 文件夹复制到源代码所在的同一文件夹:

  • lscrtlil.dll
  • lsmsilcrtl.dll
  • occmsil.dll

现在,要在 CMD 中构建此代码,请键入:

occil /NProgram.FloatToBinary /9 float_to_ieee754.c

每个参数的解释

  • /N<NameSpace>.<Class>
  • /9: C99 模式

执行此命令后,编译器将生成引用您的代码的可执行文件。

要查看生成代码的 IL 代码,只需在命令行中添加 /S 参数即可。

occil /S /NProgram.FloatToBinary /9 float_to_ieee754.c

生成 IL 代码

.corflags 3

.assembly float_to_ieee754{
}
.assembly extern mscorlib{
}
.assembly extern lsmsilcrtl{
    .ver 1:0:0:0
    .publickeytoken = (bc 9b 11 12 35 64 2d 7d )
}

.field public static uint16 * '_pctype'
.field public static void * '__stdin'
.field public static void * '__stdout'
.field public static void * '__stderr'
.namespace 'Program' {
.class public ansi sealed 'FloatToBinary' 
{.field private static valuetype 'Program.FloatToBinaryøint8[]' 'L_1' at $L_1
.data $L_1 = bytearray (
44 69 67 69 74 65 20 75
    6d 20 6e 75 6d 65 72 6f
    20 66 6c 6f 61 74 3a 20
    00 )
.field private static valuetype 'Program.FloatToBinaryøint8[]' 'L_2' at $L_2
.data $L_2 = bytearray (
25 66 00 )
.field private static valuetype 'Program.FloatToBinaryøint8[]' 'L_3' at $L_3
.data $L_3 = bytearray (
25 73 0a 00 )
.method public static hidebysig int32 'main'(int32'argc', void *'argv') cil managed{
    .locals (
        [0]    int8 * 'str/0',
        [1]    float32 'input/1'
    )
    .maxstack 3

// Line 43: int main()

L_4:
// Line 45:     float input = 0.0;

    ldloca.s    'input/1'
    ldc.r4    0
    stind.r4
// Line 46:     const int numeroDeBits = 32;

    ldloca.s    'str/0'
    ldc.i4.s    32
    conv.u4
    call    void * [lsmsilcrtl]lsmsilcrtl.rtl::malloc(uint32)
    stind.i4
// Line 48:     printf("Digite um numero float: ");

    ldsflda    valuetype 'Program.FloatToBinaryøint8[]' Program.FloatToBinary::'L_1'
    call    vararg int32 'printf'(void *, ...)
    pop
// Line 49:     scanf("%f", &input);

    ldsflda    valuetype 'Program.FloatToBinaryøint8[]' Program.FloatToBinary::'L_2'
    ldloca.s    'input/1'
    call    vararg int32 'scanf'(void *, ..., void *)
    pop
// Line 50:     floatToBinary(input, str, numeroDeBits);

    ldloc.1    
    ldloc.0    
    ldc.i4.s    32
    call    void Program.FloatToBinary::'floatToBinary'(float32, int8 *, int32)
// Line 51:     printf("%s\n", str);

    ldsflda    valuetype 'Program.FloatToBinaryøint8[]' Program.FloatToBinary::'L_3'
    ldloc.0    
    call    vararg int32 'printf'(void *, ..., void *)
    pop
// Line 52:     if(str != NULL)

    ldloc.0    
    brfalse.s    L_7
// Line 53:     free(str);     

    ldloc.0    
    call    void [lsmsilcrtl]lsmsilcrtl.rtl::free(void *)
L_7:
// Line 54:     return 0;

    ldc.i4.0    
// Line 55: }

L_5:
    ret
}
.method public static hidebysig int8 * 'strrev_t'(int8 *'str') cil managed{
    .locals (
        [0]    int8 * 'p1/0',
        [1]    int8 * 'p2/1'
    )
    .maxstack 3

// Line 5: char *strrev_t(char *str)

L_17:
// Line 7:     char *p1, *p2;

// Line 9:     if (!str || !*str)

    ldarg.0    
    brfalse.s    L_37
    ldarg.0    
    ldind.i1
    brtrue.s    L_20
L_37:
// Line 10:         return str;

    ldarg.0    
    br.s    L_18
L_20:
    ldarg.0    
    stloc.0    
    ldarg.0    
    call    uint32 'strlen'(void *)
    ldarg.0    
    add
    ldc.i4.1    
    sub
    stloc.1    
    br.s    L_26
L_25:
// Line 12:     {

// Line 13:         *p1 ^= *p2;

    ldloc.0    
    ldloc.0    
    ldind.i1
    ldloc.1    
    ldind.i1
    xor
    stind.i1
// Line 14:         *p2 ^= *p1;

    ldloc.1    
    ldloc.1    
    ldind.i1
    ldloc.0    
    ldind.i1
    xor
    stind.i1
// Line 15:         *p1 ^= *p2;

    ldloc.0    
    ldloc.0    
    ldind.i1
    ldloc.1    
    ldind.i1
    xor
    stind.i1
L_28:
    ldloc.0    
    ldc.i4.1    
    add
    stloc.0    
    ldloc.1    
    ldc.i4.1    
    sub
    stloc.1    
// Line 11:     for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)

L_26:
    ldloc.1    
    ldloc.0    
    bgt.s    L_25
L_27:
// Line 16:     }

    ldarg.0    
// Line 18: }

L_18:
    ret
}
.method public static hidebysig void 'floatToBinary'
(float32'f', int8 *'str', int32'numeroDeBits') cil managed{
    .locals (
        [0]    int32 'i/0',
        [1]    int32 'strIndex/1',
        [2]    valuetype 'Program.FloatToBinaryø__anontype_2486130647_0' 'u/2'
    )
    .maxstack 3

// Line 20: void floatToBinary(float f, char *str, int numeroDeBits)

L_41:
// Line 22:     int i = 0;

    ldloca.s    'i/0'
    ldc.i4.0    
    stind.i4
// Line 23:     int strIndex = 0;

    ldloca.s    'strIndex/1'
    ldc.i4.0    
    stind.i4
// Line 29:     u.f = f;

    ldloca.s    'u/2'
    ldc.i4.0    
    add
    ldarg.0    
    stind.r4
// Line 30:     memset(str, '0', numeroDeBits);

    ldarg.1    
    ldc.i4.s    48
    ldarg.2    
    conv.u4
    call    void * 'memset'(void *, int32, uint32)
    pop
// Line 31:

    ldc.i4.0    
    stloc.0    
    br.s    L_45
L_44:
// Line 33:     {

// Line 34:         str[strIndex++] = (u.i & (1 << 0)) ? '1' : '0';

    ldloc.1    
    ldarg.1    
    add
    ldloc.1    
    ldc.i4.1    
    add
    stloc.1    
    ldloca.s    'u/2'
    ldc.i4.0    
    add
    ldind.u4
    ldc.i4.1    
    and
    brfalse.s    L_56
    ldc.i4.s    49
    br.s    L_57
L_56:
    ldc.i4.s    48
L_57:
    conv.i1
    stind.i1
// Line 35:         u.i >>= 1;

    ldloca.s    'u/2'
    ldc.i4.0    
    add
    ldloca.s    'u/2'
    ldc.i4.0    
    add
    ldind.u4
    ldc.i4.1    
    shr.un
    stind.i4
L_47:
    ldloc.0    
    ldc.i4.1    
    add
    stloc.0    
// Line 32:     for (i = 0; i < numeroDeBits; i++)

L_45:
    ldloc.0    
    ldarg.2    
    blt.s    L_44
L_46:
// Line 36:     }

    ldloc.1    
    ldarg.1    
    add
    ldc.i4.0    
    stind.i1
// Line 39:   

    ldarg.1    
    call    int8 * Program.FloatToBinary::'strrev_t'(int8 *)
    starg.s    'str'
// Line 41: }

L_42:
    ret
}
.method private static hidebysig void '$Main'() cil managed{
    .locals (
        [0]    int32 'argc/0',
        [1]    void * 'argv/1',
        [2]    void * 'environ/2',
        [3]    void * 'newmode/3'
    )
    .entrypoint
    .maxstack 5

    call    uint16 * '__pctype_func'()
    stsfld    uint16 * '_pctype'
    call    void * '__iob_func'()
    dup
    stsfld    void * '__stdin'
    dup
    ldc.i4.s    32
    add
    stsfld    void * '__stdout'
    ldc.i4.s    64
    add
    stsfld    void * '__stderr'
    ldloca.s    'argc/0'
    ldloca.s    'argv/1'
    ldloca.s    'environ/2'
    ldc.i4.0    
    ldloca.s    'newmode/3'
    call    void '__getmainargs'(void *, void *, void *, int32, void *)
    ldloc.0    
    ldloc.1    
    call    int32 Program.FloatToBinary::'main'(int32, void *)
    call    void 'exit'(int32)
    ret
}
.method private static hidebysig int32 * '__GetErrno'() cil managed{
    .maxstack 1

    call    int32 * '_errno'()
    ret
}
.class nested public ansi sealed value sequential '__file2' {
 .pack 4 .size 16
}
.class nested public ansi sealed value sequential '__file__' {
 .pack 4 .size 32
.field public int16 'token'
.field public uint16 'flags'
.field public uint8 'hold'
.field public int32 'fd'
.field public int32 'level'
.field public int32 'bsize'
.field public uint8 * 'buffer'
.field public uint8 * 'curp'
.field public valuetype 'Program.FloatToBinaryø__file2' * 'extended'
}
.class nested public ansi sealed value sequential '__anontype_511211642_1' {
 .pack 1 .size 8
.field public int32 'quot'
.field public int32 'rem'
}
.class nested public ansi sealed value sequential '__anontype_511211642_2' {
 .pack 1 .size 8
.field public int32 'quot'
.field public int32 'rem'
}
.class nested public ansi sealed value sequential '__anontype_511211642_3' {
 .pack 1 .size 16
.field public int64 'quot'
.field public int64 'rem'
}
.class nested public ansi sealed value sequential '__anontype_2486130647_0' {
 .pack 4 .size 4
}
.class nested private explicit ansi sealed value 'int8[]' {
 .pack 1 .size 1
}
}
}
.method public static hidebysig pinvokeimpl("msvcrt.dll" cdecl) 
vararg int32 'printf'(void *) preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" cdecl) 
vararg int32 'scanf'(void *) preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" cdecl) 
uint32 'strlen'(void *) preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" cdecl) 
void * 'memset'(void *, int32, uint32) preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" stdcall) 
uint16 * '__pctype_func'() preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" stdcall) 
void * '__iob_func'() preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" stdcall) 
void '__getmainargs'(void *, void *, void *, int32, void *) preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" stdcall) 
void 'exit'(int32) preservesig{}
.method public static hidebysig pinvokeimpl("msvcrt.dll" stdcall) 
int32 * '_errno'() preservesig{}

要执行生成的 EXE/DLL,需要有两 (2) 个 DLL 与可执行文件一起。您可以从 C:\occil\bin\ 获取这两个 DLL,只需将 DLL 复制到同一个 EXE 文件夹,然后执行生成的 EXE。

构建简单的 GUI 应用程序

该编译器尚未支持创建复杂的 Windows GUI 程序所需的所有功能,但可以编译简单的程序。对于本示例,我们将创建一个简单的窗口。

注意:目前要编译使用图形界面的代码,我们仍然需要声明我们的 main 函数。

对于这个简单的示例,让我们创建一个名为 window.c 的 C 文件。

#include <windows.h>
#include <stdio.h>

const char g_szClassName[] = "WindowClass";

void createButtons(HWND hwnd)
{
    CreateWindow("button", "Beep",
        WS_VISIBLE | WS_CHILD,
        20, 50, 80, 25,
        hwnd, (HMENU)1, NULL, NULL);

    CreateWindow("button", "Quit",
        WS_VISIBLE | WS_CHILD,
        120, 50, 80, 25,
        hwnd, (HMENU)2, NULL, NULL);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
        createButtons(hwnd);
        break;
    case WM_COMMAND:
    {
        if (LOWORD(wParam) == 1)
            Beep(40, 50);

        if (LOWORD(wParam) == 2) {
            MessageBox(hwnd, "Goodbye, cruel world!", "Note", MB_OK);
            PostQuitMessage(0);
        }

        break;
    }
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowExA(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "Test window in .Net!! :)",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 230, 150,
        NULL, NULL, hInstance, NULL);

    if (hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

int main(int argc, char* argv[])
{
    STARTUPINFOA si;
    GetStartupInfoA(&si);
    int ret = WinMain(GetModuleHandleA(NULL), NULL, "", (si.dwFlags & 1) ? si.wShowWindow : 10);
    return ret;
}

要构建此源代码,需要告知编译器使用了哪些库,因此,构建源代码的命令行将是:

occil /Lkernel32 /Luser32 /9 window.c

构建完成后,我们就可以执行该应用程序了。:)

从 C 代码创建 DLL 并在 C# 中使用

现在我们知道了如何从 C 代码创建 .NET EXE。接下来,让我们从 C 代码创建 DLL 并在 C# 代码中使用它。

让我们用 C 语言创建一个简单的堆栈,为此,创建一个名为 "stack.c" 的 C 文件并将此代码插入到文件中:

#include <stdio.h>
#include <stdlib.h>

typedef struct _stack_
{
    int size;
    int totalitems;
    int* stack;
} stack;

stack* pl_initastack(int size);
void pl_push(stack* pl, int elemento, int* success);
int pl_pop(stack* pl, int* success);
int pl_top(stack *pl, int* success);
int pl_base(stack* pl, int *success);
int pl_stackfull(stack* pl);
int pl_stackempty(stack* pl);
void pl_freestack(stack *pl);
void pl_cleanstack(stack *pl);

stack* pl_initastack(int size)
{
    stack* pl = (stack*)malloc(sizeof(stack));
    pl->stack = (int*)malloc(sizeof(int) * size);
    pl->size = size;
    pl->totalitems = 0;
    return pl;
}

void pl_push(stack* pl, int elemento, int* success)
{
    if (!pl_stackfull(pl))
        pl->stack[pl->totalitems++] = elemento;
    else
        *success = 0;
}

int pl_pop(stack* pl, int* success)
{
    if (!pl_stackempty(pl))
    {
        *success = 1;
        return pl->stack[--pl->totalitems];
    }
    else
    {
        *success = 0;
        return -1;
    }
}

int pl_top(stack *pl, int* success)
{
    if (pl_stackempty(pl))
    {
        *success = 0;
        return -1;
    }
    else
    {
        *success = 1;
        return pl->stack[pl->totalitems - 1];
    }
}

int pl_base(stack* pl, int *success)
{
    if (pl_stackempty(pl))
    {
        *success = 0;
        return -1;
    }
    else
    {
        *success = 1;
        return pl->stack[0];
    }
}

int pl_stackfull(stack* pl)
{
    return pl->totalitems >= pl->size;
}

int pl_stackempty(stack* pl)
{
    return pl->totalitems == 0;
}

void pl_freestack(stack* pl)
{
    free(pl->stack);
    free(pl);
}

void pl_cleanstack(stack *pl)
{
    pl->stack = malloc(sizeof(int) * pl->size);
    pl->totalitems = 0;
}

现在,您需要使用 /Wd 选项构建此源代码。这会告诉编译器您要生成一个 DLL。因此,要构建此文件,我们使用此命令行:

occil /ostackdll.dll /Wd /9 /NStackLib.Stack stack.c

现在,让我们创建 C# 项目。对于本文,我创建了一个 .NET 4.0 的 C# 项目。

为此,您可以使用 OCC 生成的 DLL,需要在 C# 项目中设置一些选项:

  • 启用不安全代码
  • 平台目标:x86

设置好这些选项后,在引用中添加 stack.dll,并编写使用该 DLL 的代码。在这种情况下,我编写了这个简单的示例程序:

using System;
using StackLib;

namespace Stack
{
    unsafe class Program
    {
        static void Main(string[] args)
        {
            StackLib.Stack._stack_* stk = null;
            stk = StackLib.Stack.pl_initastack(5);

            int success = 1;
            Console.WriteLine("Pushing values to stack...");
            for(int i=0; (success == 1); i++)
            {
                int val = i * 10;
                StackLib.Stack.pl_push(stk, val, &success);
            }

            Console.WriteLine("Base value in stack: {0}", StackLib.Stack.pl_base(stk, &success));
            Console.WriteLine("Top value in stack.: {0}", StackLib.Stack.pl_top(stk, &success));

            Console.WriteLine("Poping values from stack");
            while(true)
            {
                int val = StackLib.Stack.pl_pop(stk, &success);
                if (success == 0)
                    break;
                Console.WriteLine("{0}", val);
            }

            StackLib.Stack.pl_freestack(stk);
            stk = null;
        }
    }
}

构建 EXE 后,不要忘记将 orangec 文件夹的 BIN 文件夹中的两个 DLL 复制过去。

使用 SQLite

现在我们知道了如何从 C 源代码创建和使用 DLL,让我们来使用 SQLite!

您可以在 \samples\sqlite3 文件夹中找到 SQLite 源代码。

要构建 SQLite 源代码,需要使用此命令行:

occil /9 /Wd /Lkernel32 sqlite3.c /Nsqlite3.sqlite

构建 SQLite 后,创建一个 C# 或任何其他您选择的 .NET 项目,添加编译后的 SQLite DLL 的引用,将项目类型设置为 x86,如果需要,启用不安全模式。在本例中,我创建了一个简单的 C# 项目并添加了一个使用 SQLite 的小程序。

using System;
using System.IO;

using sqlite3;
using lsmsilcrtl;

namespace sqliteil
{
    unsafe class Program
    {
        static string[] Names { get; } = new string[]
        {
            "Bob",
            "Tom",
            "Carlos",
            "Marcos",
            "Alexandre",
            "Alex",
            "Morgana",
            "Maria",
            "Jose",
            "Joao",
            "Marcos",
            "Gustavo",
            "Roberto",
            "Rodrigo",
            "Teste"
        };

        static int Main(string[] args)
        {
            String dbName = "dbtest.db";

            if (File.Exists(dbName))
                File.Delete(dbName);

            sqlite.sqlite3* db;
            // Create the database
            int rc = sqlite.sqlite3_open(CString.ToPointer(dbName), &db);
            if (rc != 0)
            {
                Console.WriteLine("Fail to create the database :(");
                return -1;
            }

            // Create the table
            sqlite.sqlite3_stmt* stmt;
            sqlite3.sqlite.sqlite3_prepare_v2(db, CString.ToPointer
            ("CREATE TABLE demo (name TEXT, age INTEGER);"), -1, &stmt, null);
            rc = sqlite.sqlite3_step(stmt);
            if (rc != 101)
            {
                Console.WriteLine("Fail to create the table :(");
                return -1;
            }
            sqlite.sqlite3_finalize(stmt);

            // Insert some data in table
            foreach (var name in Names)
            {
                var insertLine = String.Format("insert into demo (name, age) 
                values ('{0}', {1});", name, new Random().Next(1, 99));
                var query = CString.ToPointer(insertLine);
                sqlite.sqlite3_prepare_v2(db, query, insertLine.Length, &stmt, null);
                rc = sqlite.sqlite3_step(stmt);
                if (rc != 101)
                {
                    Console.WriteLine("Fail to insert the name: {0}", name);
                }
                sqlite.sqlite3_finalize(stmt);
            }

            // Read the inserted data...
            var select = "SELECT * FROM demo;";
            rc = sqlite.sqlite3_prepare_v2(db, CString.ToPointer(select), select.Length, &stmt, null);
            if(rc == 0)
            {
                bool done = false;
                while(!done)
                {
                    switch(rc = sqlite.sqlite3_step(stmt))
                    {
                        case 5:
                        case 101:
                            done = true;
                            break;
                        case 100:
                            {
                                string name = 
                                   new CString(sqlite.sqlite3_column_text(stmt, 0)).ToString();
                                int age = sqlite.sqlite3_column_int(stmt, 1);
                                Console.WriteLine("Name: {0} -- Age: {1}", name, age);
                                rc = 0;
                            }
                            break;
                        default:
                            done = true;
                            break;
                    }
                }
            }

            sqlite.sqlite3_close(db);
            return 0;
        }
    }
}

该项目位于 SQLite 测试文件夹内。

尚未实现的功能

  1. 复数未实现。
  2. 原子操作未实现。
  3. 线程和线程局部存储未实现。
  4. 运行时库是 msvcrtl.dll,并且不支持 C11 或 C99 对 CRTL 的添加。
  5. 数组未实现为托管数组,而是作为指向非托管内存的指针。
  6. 数组类型实际上实现为 .NET 类。
  7. 可变参数列表的处理方式类似于 C#,而不是 C(除非在调用非托管函数时)。
  8. 当可变参数列表传递给非托管代码时会进行封送处理,但这仅限于简单类型。
  9. 为传递在托管和非托管代码之间的函数指针(例如,用于 qsort 和 WNDPROC 风格的函数)生成了 thunks。但当指针放在结构中时,您需要给编译器一个提示。在函数指针定义中使用 CALLBACK,并将 callback 定义为 stdcall 函数。
  10. 在从非托管代码到托管代码的转换(由传递给非托管代码的函数指针使用)的 thunks 中,会进行封送处理,但这仅限于简单类型。
  11. 可变长度数组和 'alloca' 是通过托管内存分配器实现的,而不是通过 'localalloc' MSIL 函数。
  12. 通过值传递给函数的结构在调用前会被复制到临时变量。
  13. 原生编译器中的许多编译器优化目前已关闭。
  14. 编译器不允许使用无原型函数。

有任何问题吗?

欢迎提问!:)

历史

  • 2019 年 12 月 16 日
    •  
  • 2019 年 9 月 8 日
    • 添加了新的 OrangeC 编译器发布版本。
  • 2017 年 10 月 12 日
    • 添加了文章第二部分的链接。
    • 更新了 zip 文件,包含新的可执行文件。
  • 2017 年 3 月 9 日
    • 添加了关于 DotNetPeLib 的文章链接。
  • 2017 年 3 月 8 日
    • 更新了 zip 文件,包含新的可执行文件。
    • 更新了文章中的 occ 文件夹。
    • 添加了项目的官方链接。
  • 2017 年 2 月 10 日
    • 更新了“尚未实现的功能”部分。
  • 2016 年 11 月 5 日
    • 更新了可执行文件。
    • 添加了 DotNetPeLib 的链接。
    • 更改了示例代码,使用 typedef/struct 的真实名称而不是 "void*"。
    • 删除了关于使用 Borland 构建的说明。
    • 移除了对 ILASM 的引用。
    • 添加了“尚未实现的功能”部分。
  • 2016 年 9 月 22 日
    • 添加了“构建简单的 GUI 应用程序”部分。
    • 添加了“使用 SQLite”部分。
    • 更新了可供下载的可执行文件。
  • 2016 年 9 月 13 日
    • 文章创建。
© . All rights reserved.