繁体   English   中英

ANSI C作为C#项目的核心? 这可能吗?

[英]ANSI C as core of a C# project? Is this possible?

我正在编写一个非GUI应用程序,我希望它是OS X和Windows之间的跨平台。 我正在考虑以下架构,但我不知道它是否适用于Windows端:

(平台特定入口点) - > ANSI C主循环=> ANSI C模型代码执行数据处理/逻辑=>(平台特定帮助程序)

所以我打算用常规的ANSI C编写核心内容,因为A)它应该是独立于平台的,B)我对C,C非常熟悉它可以完成工作并做得很好

(平台特定的入口点)可以写成任何必要的工作,这是少量的代码,对我来说无关紧要。

(平台特定的帮助者)是棘手的事情。 这就像解析XML,访问数据库,图形工具包等等。 在C中不容易的事情。现代语言/框架将免费提供的东西。 在OS X上,这段代码将用Objective-C与Cocoa连接编写。 在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和朋友在这里做得对(也许你没有,但我这样做)

简短回答: 是的。 您可以从.NET轻松访问非托管代码,但您必须整理数据。

答案长: 不要这样做。 你知道单声道项目吗? 它是.NET的x平台实现。 他们有点落后于微软,但他们仍然提供适用于许多人的解决方案。 我强烈建议尽可能保留托管代码,如果你正在使用C代码,你就会破坏.NET的目的。 这也有助于将项目复杂性降低十倍。

如果您需要C ANSI进行低级访问,我建议您向.NET内核公开一个经过良好测试小型 ANSI ANSI api,以执行任何低级别的操作。

C#Core <==>小C ANSI助手库

你为什么不用c ++做这一切? 你可以点击你所有的平台并获得你说C没有的所有东西。 C#只适用于点网络,c / c ++仍可在Windows上运行,只需获取您需要的api调用即可。

我喜欢Aren的答案(看看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函数)的指针,加上一个Callback typedef。 我们使用__declspec(dllexport),以便C#代码可以调用它。

在C#方面,我们有一个委托声明,它大致类似于C中的typedef,以及一个我们想要传递给C的函数“PrintOut”。

假设您将C代码编译为名为Foo.dll的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);
}

希望有所帮助!

首先,回答一个特定的担心:您可以将委托编组为您的本机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声明等。

完全没有理由使用ANSI C over C ++。 另外,如果你有C ++代码,编写一个用于C#的C ++ / CLI包装器是非常简单的(据我所知)并且C ++不会添加两个浮点数比C更慢(许多其他操作实际上更快,喜欢排序)。 除此之外,C ++对于你可以用它做什么非常灵活。

C ++ < - > C ++ / CLI < - > C#可能是最简单的方法,因为C ++ / CLI互操作可以轻松地双向工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM