Click here to Skip to main content
13,194,662 members (70,723 online)
Click here to Skip to main content
Add your own
alternative version

Stats

4.9K views
52 downloads
5 bookmarked
Posted 12 Oct 2017

Compiling Your C Code to .NET - Part 2

, 12 Oct 2017
Rate this:
Please Sign up or sign in to vote.
With this new OrangeC/C++ compiler back-end, you can compile your C code to .NET.

Articles about OrangeC to .NET

Table of Contents

Introduction

To allow the support of .NET methods, classes, properties, enums .... has been implemented in OrangeC, a support for C# like language, for example:

int a = 10;
printf("%s", a.ToString());

Another feature, that came from C++, has been enabled to use is the "using namespace", for example:

using namespace System;
using namespace System::IO;

So, let's look how to use those new features of OrangeC compiler to .NET.

Using .NET Types

The .NET types are nothing more than .NET classes, so, with OrangeC, you can use these classes and methods as normal types in C. To make it more simple to understand, let's build a small example, using a .NET string class:

int main()
{
  System::String str("Hello World!!");
  return 0;
}

With this code, we created an instance of class String, for convenience, was implementing inside of compiler, some keywords to handle the most common classes of .NET, that is:

  1. Object
  2. String

So, to use these types using the native keyword, we have:

  1. __object
  2. __string

Let's look at a small example:

int main()
{
  __string str("Hello World!!");
  __object obj = (__object)str;

  printf("%s\n", str);
  printf("%s\n", (__string)obj);
  return 0;
}

Let's look at one more of using .NET types example:

int main()
{
  System::DateTime dt(2017,10,10);
  return 0;
}

Managed and Unmanaged Arrays

To avoid problems of compatibility between legacy code and new codes, a syntactic variation was implemented to differentiate between arrays types, so, to create a managed array, we use the [] before the variable name, and, to create an unmanaged array, we use the [] after the variable name. To make it more clear, let's make a small example:

int main()
{                         
  int []a = { 0, 1, 2, 3, 4, 5 };   // Managed array
  int b[] = { 0, 1, 2, 3, 4, 5 };   // Unmanaged array
 
  return 0;
}

Maybe you are thinking, what exactly is the difference between the managed and unmanaged array?
So, to answer this, let's look at the generated code to each kind of array (I have used a decompiler to get this code):

public static unsafe int main(int argc, void* argv)
{
    // The managed array
    int[] a = new int[] { 0, 1, 2, 3, 4, 5 };

    // The unmanaged array
    int32[24] b = null;
    *(&b + 4) = 1;
    *(&b + 8) = 2;
    *(&b + 12) = 3;
    *(&b + 16) = 4;
    *(&b + 20) = 5;
    return 0;
}

The navigation into array is still the same:

int main()
{                         
  int []a = { 0, 1, 2, 3, 4, 5 }; // Managed array
  int b[] = { 0, 1, 2, 3, 4, 5 }; // Unmanaged array 
 
  printf("Printing all elements of managed array: ");
  for(int i=0;i<a.Length;i++) // Look at the usage of property "Length"
  {
    if(i != 0)
      printf(", ");
    printf("%d", a[i]);
  }
  printf("\n");
 
  printf("Printing all elements of unmanaged array: ");
  for(int i=0;i<sizeof(b)/sizeof(int);i++)
  {
    if(i != 0)
      printf(", ");
    printf("%d", a[i]);
  }
 
  printf("\n");
  return 0;
}

Using .NET Methods

The usage of .NET methods is like C#:

  • <Instance>.<Method>([args]);

The difference is with enums and static class

  • [Namespace]::<Static class>::<Method | Property | Enum>[ ( [args] ) ];

Let's look at one single example, that shows these cases:

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

using namespace System;
using namespace System::Runtime;
using namespace System::Reflection;
using namespace System::Reflection::Emit;

int main()
{
  AppDomain ad = AppDomain::CurrentDomain;
  AssemblyName am("TestAsm");
                                                 
  AssemblyBuilder ab = ad.DefineDynamicAssembly(am, AssemblyBuilderAccess::Save);
  ModuleBuilder mb = ab.DefineDynamicModule("testmod", "TestAsm.exe");
  TypeBuilder tb = mb.DefineType("mytype", TypeAttributes::Public);
  MethodBuilder metb = tb.DefineMethod("hi", MethodAttributes::Public | 
                                        MethodAttributes::Static, NULL, NULL);
  ab.SetEntryPoint(metb);
    
  ILGenerator il = metb.GetILGenerator(); 
  il.EmitWriteLine("Hello World");
  il.Emit(OpCodes::Ret);
  tb.CreateType();
  ab.Save("TestAsm.exe");

  Console::WriteLine("TestAsm.exe created!");

  return 0;
}

Let's build one more example, implementing a function that receives a .NET type as parameter and uses some sophisticated methods call:

#include <stdio.h>

void test(System::DateTime dt, System::String &str)
{
  str = dt.ToString("dd/MM/yyyy");
}

int main()
{                         
  __string str;
  System::DateTime dt1 = System::DateTime::Today;
  System::DateTime dt2 = dt1.AddDays(30);
 
  str =  dt1.ToString("dd,MM,yyyy") + "/" + dt2.ToString("dd.MM.yy");
 
  __string part1 = str.Substring(0, str.IndexOf("/"));
  __string part2 = str.Substring(str.IndexOf("/") + 1);
 
  str = str.Replace(",", "").Replace("/", "").Replace("10", "Hi!");
 
  printf("Part1 = %s\nPart2 = %s\nNew string = %s\n", part1, part2, str);
 
  test(dt1, str);
 
  printf("%s\n", str);  
 
  return 0;
}

Finally, we will build a mix of managed and unmanaged code, for this, we will build a linked list, where the struct of linked list hold managed types:

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

int getAge(System::DateTime reference, System::DateTime birthday);

typedef struct node
{
  __string name;
  System::DateTime bornDate;
 
  struct node* next;
} node_t;

void push(node_t* head, __string name, System::DateTime born)
{
    node_t* current = head;
    while (current->next != NULL)
        current = current->next;
       
    current->next = (node_t*)malloc(sizeof(node_t));
    current->next->name = name;
    current->next->bornDate = born;
    current->next->next = NULL;
}

void print_list(node_t * head) {
    node_t * current = head;

    System::DateTime today = System::DateTime::Today;
    while (current != NULL) {
        System::Console::WriteLine(((__string)"").PadLeft(80, System::Convert::ToChar("-")));
        System::Console::WriteLine("Name: {0}\nBorn date: {1}\nAge: {2}\n", 
        current->name, current->bornDate.ToString("dd/MM/yyyy"), getAge(today, current->bornDate));
        current = current->next;
    }
}

int getAge(System::DateTime reference, System::DateTime birthday)
{
  int age = reference.Year - birthday.Year;
  if(System::DateTime::op_LessThan(reference, birthday.AddYears(age)))
    age--;
    
  return age;
}

int main()
{            
  node_t* head = (node_t*)malloc(sizeof(node_t));
  head->name = "Alexandre";
  head->bornDate = System::DateTime::Today;
  head->next = NULL;
 
  System::DateTime today = System::DateTime::Today;
  for(int i=0;i<15;i++)
    push(head, "Teste", today.AddDays(i + 1).AddYears(-24));   
    
  print_list(head);
      
  return 0;
}

Using Try / Catch / Finally

Exception systems greatly help the developer to handle errors so that C code becomes more compatible with the .NET error system and exception system, we implement support for try / catch / finally, the usage of these commands like in C#, so, let's take a look:

using namespace System;
using namespace System::IO;

int main()
{
  __try
  {
    File.Open("some file that doesn't exist", FileMode::Open);
  }
  __catch (Exception e)
  {
    Console::WriteLine(e.Message);
  }
  __finally
  {
    printf("Finally!");
  }
}

History

  • 12-Oct-2017: Article created

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

No Biography provided

You may also be interested in...

Comments and Discussions

 
Generalexcellent! Pin
Southmountain14-Oct-17 13:17
memberSouthmountain14-Oct-17 13:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171018.2 | Last Updated 12 Oct 2017
Article Copyright 2017 by Alexandre Bencz
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid