ANSI C как ядро ​​проекта C #?Это возможно? - PullRequest
4 голосов
/ 16 июня 2010

Я пишу приложение без графического интерфейса, которое я хочу использовать в качестве кроссплатформенного между OS X и Windows.Я смотрю на следующую архитектуру, но я не знаю, будет ли она работать на стороне Windows:

(точка входа для платформы) -> Основной цикл ANSI C => Код модели ANSI C, выполняющий данныеобработка / логика => (помощники для конкретной платформы)

Итак, основной материал, который я планирую написать на обычном ANSI C, потому что: A) он должен быть независимым от платформы, B) я очень доволен C,C) Он может выполнять свою работу и делать это хорошо

(точка входа для конкретной платформы) может быть написано на любом уровне, необходимом для выполнения работы, это небольшой объем кода, для меня это не имеет значения.

(помощники, работающие на платформе).Это такие вещи, как синтаксический анализ XML, доступ к базам данных, графические инструменты и прочее.Вещи, которые не легко в C. Вещи, которые современные языки / рамки будут давать бесплатно.На OS X этот код будет написан в Objective C, взаимодействующем с Какао.В Windows я думаю, что лучше всего использовать C #

Так что в Windows моя архитектура (упрощенная) выглядит так:

(C # или C?) -> ANSI C -> C #

Возможно ли это?Некоторые мысли / предложения на данный момент ..

1) Скомпилировать мое ядро ​​C как .dll - это нормально, но, похоже, нет способа вызвать моих помощников на C #, если я не могу каким-то образом получить указатели на функции и передать ихна мой взгляд, но это маловероятно

2) Скомпилируйте C .exe и C # .exe и попросите их обмениваться данными через общую память или какой-либо IPC.Я не совсем против этого, но он, очевидно, представляет большую сложность, поэтому он не кажется идеальным

3) Вместо C #, использующего C ++, он дает мне некоторые полезные вещи для управления данными и хороший вспомогательный код.И я могу смешать это довольно легко.И работу, которую я делаю, возможно, легко перенести на Linux.Но мне действительно не нравится C ++, и я не хочу, чтобы это превратилось в сторонний библиотечный фестиваль.Не то, чтобы это была огромная сделка, но это 2010 год ... все для базового управления данными должно быть встроено. И нацеливание на Linux на самом деле не является приоритетом.

Обратите внимание, что никакие "общие" альтернативы не подходят, как предложено в другихпохожие вопросы по ТАК я видел;java, RealBasic, mono .. это приложение с чрезвычайно высокой производительностью, делающее мягкие программы в реальном времени для игр / симуляций, мне нужны C & друзья здесь, чтобы сделать это правильно (возможно, вы этого не делаете, но я делаю)

Ответы [ 5 ]

6 голосов
/ 16 июня 2010

Краткий ответ: Да. Вы можете легко получить доступ к неуправляемому коду из .NET, но вам придется маршалировать ваши данные.

Длинный ответ: Не делайте этого. Вы знаете о монопроекте ? Это реализация платформы .NET для платформы x. Они немного отстают от Microsoft, но они все еще предлагают решение, которое работает для многих. Я бы настоятельно рекомендовал сохранить в управляемом коде, если это вообще возможно, вы побеждаете цель .NET, если вы знакомы с кодом C. Это также поможет уменьшить сложность вашего проекта в десять раз.

Если вам требуется C ANSI для низкоуровневого доступа, я предлагаю вам предоставить small & хорошо протестированный C ANSI api вашему ядру .NET для выполнения любого низкоуровневого прочее.

C # Core <==> Небольшая вспомогательная библиотека C ANSI

1 голос
/ 17 июня 2010

Прежде всего, чтобы ответить на один конкретный вопрос: вы можете маршалировать делегатов как указатели функций на ваш родной код на C - фактически, он «просто работает», а P / Invoke позаботится обо всей упаковке:

// C#
class ManagedEntryPoint {

    [DllImport("core", CallingConvention=CallingConvention.Cdecl)]
    static extern void NativeEntryPoint(Func<int, int, float> helper);

    static float Helper(int, int) { ... }

    static void Main() {
        NativeEntryPoint(Helper);
    }
}

// C
void NativeEntryPoint(float (*helper)(int, int)) {
    float x = helper(1, 2);
    ...
}

Однако я не вижу в этом особого смысла - проще использовать компилятор C ++ / CLI. Обратите внимание, что это не означает, что вы на самом деле должны использовать C ++ - вы можете придерживаться подмножества C, совместимого с C ++, что составляет 95% (я бы ожидал, что единственное, что вам нужно сделать иначе на практике явно приводят возврат malloc). Вы компилируете свои собственные функции C как собственный .lib, а затем связываете их с исполняемым файлом, скомпилированным с /clr. C ++ / CLI позаботится обо всем самом маршалинге, и вам не нужно будет писать объявления P / Invoke и тому подобное.

1 голос
/ 16 июня 2010

Мне нравится ответ Арен (посмотрите на Mono), но если вы действительно хотите использовать C + C #, вы можете использовать SWIG , чтобы несколько автоматически создавать обертки кода C.У него есть кривая обучения, но если количество функций C, которые вы хотите вызвать из C #, достаточно велико, оно того стоит.SWIG не поддерживает Objective C "из коробки", но есть ветвь с не полностью законченной поддержкой.

Обновление: о, вы хотите в первую очередь вызвать C # из C?Извините, SWIG не предназначен для этого.C # действительно позволяет это, однако.Вы можете использовать либо точку входа C #, либо C / C ++ (точка входа C #, вероятно, проще), и вы можете передавать указатели на функции C (делегаты) в код C.

Допустим, вы хотите передатьФункция void (string) из C # в C. Прежде всего, я не знаю, как код C может напрямую получать указатели на функции C # (это может быть возможно, я просто не знаю как.) Вместо этого я бы запустил программув коде C # и код C # передает себя в код C.

Примерно так:

// Visual C code:
// (.NET functions use the __stdcall calling convention by default.)
typedef void (__stdcall *Callback)(PCWSTR);
void __declspec(dllexport) Foo(Callback c)
{
    c(L"Hello world");
}

// C# code:
// (A delegate declaration can include marshaling commands that
// control how argument types are converted.)
public delegate void Callback([MarshalAs(UnmanagedType.LPWStr)] string message);
void PrintOut(string message) { Console.WriteLine(message); }

Здесь у нас есть функция C "Foo", которая может получить указатель наC # функция "PrintOut" (или функция C в этом отношении), а также обратный вызов typedef.Мы используем __declspec (dllexport), чтобы его мог вызвать код C #.

На стороне C # у нас есть объявление делегата, которое примерно аналогично typedef в C, и функция "PrintOut", которую мы хотимперейдите к C.

Если вы скомпилируете свой код C в DLL с именем Foo.dll, вам потребуется объявление C # P / Invoke и код, который фактически вызывает Foo:

[DllImport("Foo")]
public static extern void Foo(Callback c);

public void CallFoo()
{
    Foo(PrintOut);
}

Вышеприведенное, вероятно, сначала будет работать, но есть одна «ошибка»: приведенный выше код оборачивает PrintOut в делегат, и сборщик мусора в конце концов освободит делегат, если вы не сохраните ссылку на него.Поэтому, если вы хотите, чтобы код C имел постоянную ссылку на метод C #, мы должны изменить приведенный выше код C #, чтобы сохранить ссылку на делегат:

[DllImport("Foo")]
public static extern void Foo(Callback c);

static Callback PrintOutRef; // to prevent garbage collection of the delegate

public void CallFoo()
{
    Foo(PrintOutRef = PrintOut);
}

Надеюсь, что это поможет!

1 голос
/ 16 июня 2010

Почему бы вам не сделать все это в c ++? Вы можете поразить все свои платформы и получить все то, чего, как вы говорите, C не имеет. C # предназначен только для работы с точечной сетью, c / c ++ по-прежнему работает на Windows, просто получите вызов API, который вам нужен для всего, что вы пытаетесь сделать.

0 голосов
/ 16 июня 2010

Нет никакой причины использовать ANSI C над C ++.Кроме того, если у вас есть код C ++, написание оболочки C ++ / CLI для использования в C # очень тривиально (насколько я знаю), и C ++ не будет добавлять два числа с плавающей запятой медленнее, чем будет C (многие другие операции на самом деле быстрее,вроде сортировка).В дополнение к этому, C ++ довольно гибок в отношении того, что вы можете с ним делать.

C ++ <-> C ++ / CLI <-> C #, вероятно, самый простой способ, поскольку взаимодействие C ++ / CLIможет легко работать в обоих направлениях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...