C++/CLI:第一流的CLI语言

简介:
1. 简介

  本文并不是为了奉承C++/CLI的辉煌,也不是为了贬低其它如C#或者VB.NET等语言,相反,这只是一个非官方的、以一个喜欢这种语言的非 微软 雇员身份来论证C++/CLI有它的自己的唯一的角色,可作为第一流的.NET编程语言。

  一个不断在新闻组和技术论坛上出现的问题是,当象C#和VB.NET这样的语言更适合于这种用途时,为什么要使用C++来开发.NET应用 软件 。通常这样一些问题后面的评论说是,C++语法是怎样的复杂和令人费解,C++现在是怎样一种过时的语言,还有什么VS.NET 设计 者 已不再像支持C#和VB.NET一样继续支持C++。其中一些猜疑是完全荒谬的,但有些说法部分正确。希望本文有助于澄清所有这些围绕C++/CLI语言 及其在VS.NET语言层次中的地位的疑惑,神秘和不信任。请记住,本作者既不为微软工作也没有从微软那里取得报酬,只是想从技术上对C++/CLI作一 评判。

   2. 快速简洁的本机interop

  除了P/Invoke机制可用在另外的象C#或 VB.NET这样的语言外,C++提供了一种独有的interop机制,称作C++ interop。C++ interop比P/Invoke直观得多,因为你只是简单地#include需要的头文件,并与需要的库进行链接就能象在本机C++中一样调用任何函 数。另外,它比P/Invoke速度快--这是很容易能证明的。现在,可争辩的是在实际应用软件的开发中,经由C++ interop获得的性能好处与花在用户接口交互、数据库存取、 网络 数据转储、复杂数学算法等方面的时间相比可以被忽略,但是事实是在有些情况下,甚至通过每次interop调用节省的几个纳秒也能给全局应用 程序 性 能/响应造成巨大影响,这是绝对不能被忽视的。下面有两部分代码片断(一个是使用P/Invoke机制的C#程序,一个是使用C++ Interop机制的C++程序),我分别记录了其各自代码重复执行消耗的时间(毫秒)。不管你如何解释这些数据,不管这会对你的应用程序产生什么影响, 全是你的事。我仅打算事实性地指出,C++代码的执行速度要比C#(其中使用了较多的本机interop调用)快。

  1) C#程序(使用P/Invoke)

[SuppressUnmanagedCodeSecurity] 
[DllImport("kernel32.dll")]
static extern uint GetTickCount();
[SuppressUnmanagedCodeSecurity] 
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint GetWindowsDirectory(
[Out] StringBuilder lpBuffer, uint uSize);
static void Test(int x)
{
StringBuilder sb = new StringBuilder(512);
for (int i = 0; i < x; i++)
GetWindowsDirectory(sb, 511);
}
static void DoTest(int x)
{
uint init = GetTickCount();
Test(x);
uint tot = GetTickCount() - init;
Console.WriteLine("Took {0} milli-seconds for {1} iterations",tot, x);
}
static void Main(string[] args)
{
DoTest(50000);DoTest(500000);DoTest(1000000);DoTest(5000000);
Console.ReadKey(true);
}

  2) C++程序(使用C++ Interop)

void Test(int x)
{
TCHAR buff[512];
for(int i=0; i<x; i++)
GetWindowsDirectory(buff, 511);
}
void DoTest(int x)
{
DWORD init = GetTickCount();
Test(x);
DWORD tot = GetTickCount() - init;
Console::WriteLine("Took {0} milli-seconds for {1} iterations",tot, x);
}
int main(array<System::String ^> ^args)

DoTest(50000);DoTest(500000);DoTest(1000000);DoTest(5000000);
Console::ReadKey(true);
return 0;
}

  3) 速度比较

重复次数 C# 程序 C++程序
50,000 61 10
500,000 600 70
1,000,000 1162 140
5,000,000 6369 721
   
  其性能差别真是令人惊愕!这的确是说明为什么要使用C++ /CLI的一个好理由,如果你在使用本机interop进行开发,那么性能!完全由于性能,我就将被迫借助本机interop来实现并非基于web的. NET应用程序。当然,为什么我想要使用.NET来开发需要大量本机interop技术的应用程序完全是另外一个问题。

  如果你仍怀疑这种性能优势,有另外的理由来说明你为什么不得不使用C++/CLI而不是C#或VB.NET——源码膨胀!下面是一个C++函数的例子,它使用了IP帮助者API来枚举一台机器上的网络适配器并且列出与每个适配器相联系的所有IP地址。

  4) 枚举n/w适配器的C++代码

void ShowAdapInfo()
{
PIP_ADAPTER_INFO pAdapterInfo = NULL;
ULONG OutBufLen = 0;
//得到需要的缓冲区大小
if(GetAdaptersInfo(NULL,&OutBufLen)==ERROR_BUFFER_OVERFLOW)
{
int divisor = sizeof IP_ADAPTER_INFO;
#if _MSC_VER >= 1400
if( sizeof time_t == 8 ) divisor -= 8;
#endif
pAdapterInfo = new IP_ADAPTER_INFO[OutBufLen/divisor];
//取得适配器信息
if( GetAdaptersInfo(pAdapterInfo, &OutBufLen) != ERROR_SUCCESS )
{//调用失败 }
else 
{
int index = 0;
while(pAdapterInfo)
{
Console::WriteLine(gcnew String(pAdapterInfo->Description));
Console::WriteLine("IP Address list : ");
PIP_ADDR_STRING pIpStr = &pAdapterInfo->IpAddressList;
while(pIpStr)
{
Console::WriteLine(gcnew tring(pIpStr->IpAddress.String));
pIpStr = pIpStr->Next;
}
pAdapterInfo = pAdapterInfo->Next;
Console::WriteLine();
}
}
delete[] pAdapterInfo;
}
}

  现在让我们看一个使用P/Invoke的C#版本。

  5) 使用P/Invoke技术的C#版本

const int MAX_ADAPTER_NAME_LENGTH = 256;
const int MAX_ADAPTER_DESCRIPTION_LENGTH = 128;
const int MAX_ADAPTER_ADDRESS_LENGTH = 8;
const int ERROR_BUFFER_OVERFLOW = 111;
const int ERROR_SUCCESS = 0;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct IP_ADDRESS_STRING
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Address;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct IP_ADDR_STRING
{
public IntPtr Next;
public IP_ADDRESS_STRING IpAddress;
public IP_ADDRESS_STRING Mask;
public Int32 Context;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct IP_ADAPTER_INFO
{
public IntPtr Next;
public Int32 ComboIndex;
[MarshalAs(UnmanagedType.ByValTStr, 
SizeConst = MAX_ADAPTER_NAME_LENGTH + 4)]
public string AdapterName;
[MarshalAs(UnmanagedType.ByValTStr, 
SizeConst = MAX_ADAPTER_DESCRIPTION_LENGTH + 4)]
public string AdapterDescription;
public UInt32 AddressLength;
[MarshalAs(UnmanagedType.ByValArray, 
SizeConst = MAX_ADAPTER_ADDRESS_LENGTH)]
public byte[] Address;
public Int32 Index;
public UInt32 Type;
public UInt32 DhcpEnabled;
public IntPtr CurrentIpAddress;
public IP_ADDR_STRING IpAddressList;
public IP_ADDR_STRING GatewayList;
public IP_ADDR_STRING DhcpServer;
public bool HaveWins;
public IP_ADDR_STRING PrimaryWinsServer;
public IP_ADDR_STRING SecondaryWinsServer;
public Int32 LeaseObtained;
public Int32 LeaseExpires;
}
[DllImport("iphlpapi.dll", CharSet = CharSet.Ansi)]
public static extern int GetAdaptersInfo(IntPtr pAdapterInfo, ref int pBufOutLen);
static void ShowAdapInfo()
{
int OutBufLen = 0; 
//得到需要的缓冲区大小
if( GetAdaptersInfo(IntPtr.Zero, ref OutBufLen) == 
ERROR_BUFFER_OVERFLOW )
{
IntPtr pAdapterInfo = Marshal.AllocHGlobal(OutBufLen); 
//取得适配器信息
if( GetAdaptersInfo(pAdapterInfo, ref OutBufLen) != ERROR_SUCCESS )
{ //调用失败了 }
else{
while(pAdapterInfo != IntPtr.Zero)
{
IP_ADAPTER_INFO adapinfo = 
(IP_ADAPTER_INFO)Marshal.PtrToStructure(
pAdapterInfo, typeof(IP_ADAPTER_INFO));
Console.WriteLine(adapinfo.AdapterDescription);
Console.WriteLine("IP Address list : ");
IP_ADDR_STRING pIpStr = adapinfo.IpAddressList;
while (true){
Console.WriteLine(pIpStr.IpAddress.Address);
IntPtr pNext = pIpStr.Next;
if (pNext == IntPtr.Zero)
break;
pIpStr = (IP_ADDR_STRING)Marshal.PtrToStructure(
pNext, typeof(IP_ADDR_STRING));
}
pAdapterInfo = adapinfo.Next;
Console.WriteLine(); 
}
}
Marshal.FreeHGlobal(pAdapterInfo);
}

}















本文转自朱先忠老师51CTO博客,原文链接:http://blog.51cto.com/zhuxianzhong/59841 ,如需转载请自行联系原作者



相关文章
|
1月前
|
算法 编译器 C语言
C++语言的“Hello World”
C++语言的“Hello World”
14 0
|
1月前
|
编译器 C++
C++语言中const的用法
C++语言中const的用法
13 0
|
1月前
|
存储 编译器 C++
在C++语言中计算并打印出两个数的求和
在C++语言中计算并打印出两个数的求和
22 0
|
1月前
|
C++
C++语言中流程控制
C++语言中流程控制
14 0
|
1月前
|
程序员 API C语言
在C++语言的标准I/O库
在C++语言的标准I/O库
10 0
|
1月前
|
C++
在C++语言中return语句
在C++语言中return语句
14 0
在C++语言中return语句
|
1月前
|
程序员 C++ 索引
在C++语言中Vector的命名空间的作用
在C++语言中Vector的命名空间的作用
15 0
|
6天前
|
缓存 编译器 API
NumPy与其他语言(如C/C++)的接口实践
【4月更文挑战第17天】本文介绍了NumPy与C/C++的接口实践,包括Python与C/C++交互基础、NumPy的C API和Cython的使用。通过案例展示了如何将C++函数与NumPy数组结合,强调了内存管理、类型匹配、错误处理和性能优化的最佳实践。掌握这些技能对于跨语言交互和集成至关重要。
|
16天前
|
程序员 C++
C++语言模板学习应用案例
C++模板实现通用代码,以适应多种数据类型。示例展示了一个计算两数之和的模板函数`add&lt;T&gt;`,可处理整数和浮点数。在`main`函数中,展示了对`add`模板的调用,分别计算整数和浮点数的和,输出结果。
12 2
|
29天前
|
Java API 开发工具
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用(三)
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用
30 0

热门文章

最新文章

相关实验场景

更多