当我们在C#和C ++中声明一个数组时有什么区别?

int[] arr = new int[3]; // C# int arr[3]; //C++ 

c ++中的数组声明将为三个整数分配一块内存。

我可以假设语言c#相同,但由于以下事实我不能。

c#中的每个变量都是struct或class或enum,As Array是一个类,arr应该是Array类的对象。 Intellisense还表明arr有许多与Array类函数相同的成员函数,但是Array是一个抽象类,因为我们无法实例化一个抽象类,arr可以是任何其他可能实现Array类的类的对象

如果我的演绎是正确的,我想知道

  1. 哪个类是arr的对象?

如果我的演绎错了

  1. 我想知道我哪里错了?
  2. 哪个Class数组是一个对象?

难以比较两者,它们几乎没有共同之处。 C ++从C语言inheritance了这个数组语法和行为。 设计时只考虑了一个目标,只考虑了尽可能快。 你使用的“分配”这个词已经与运行时发生的不匹配,int [3]语法只是保留了空间。 确切地说,发生的位置取决于声明的位置,在函数内部,它将在堆栈帧上保留空间,在外部它将在数据部分中保留空间。

没有执行保证,元素没有初始化,运行时不跟踪数组的大小,没有索引检查。 尽可能快地发布数十亿个错误和数万个恶意软件攻击的function。 缓冲区溢出是C或C ++程序中的标准问题,当它破坏内存,随机覆盖其他变量或函数的返回地址时,很难诊断出错误。 或者简单地使用数据(恶意软件攻击向量)来编写程序。

当然不是C#方式。 数组类型是.NET Framework中的引用类型,它们的存储始终从GC堆分配。 如果数组很小(小于85KB),快生成#0堆,否则来自大对象堆。 抖动和CLR中有很多很多胶水可以使它们尽可能快地完成,尽管它们有以下保证:

  • 有专门的IL操作码来创建一个数组, Opcodes.NewArr ,抖动将它转换为直接调用CLR。
  • 这个辅助函数动态创建数组类型(如果它还不存在)(与Type.MakeArrayType()比较),从GC堆分配存储并初始化对象,设置Length属性并初始化数组成员以便它们都具有他们的默认(T)值。
  • 再次访问代码中的数组元素会产生专用的IL操作码,如Opcodes.LdElem 。 抖动将它们转换为机器代码指令,用于检查数组边界并访问数组元素。
  • 其他数组成员生成对内部SZArrayHelper类的直接调用,并对其进行优化,以便为一维数组生成尽可能快的代码。
  • 抖动中的代码优化器寻找消除数组绑定检查的机会,可以从代码中看到索引表达式不能超出范围。 这通常是可能的,特别是当您使用foreach或编写使用数组的Length属性的for(;;)循环时,数组访问的速度与C中的等效数一样快。
  • 垃圾收集器具有内置的数组知识,它在压缩堆时重新排列引用类型的数组元素,因此可以在迭代数组的代码中顺序访问它们。 非常非常重要的现代处理器依赖CPU缓存来快速访问内存。 这是托管代码可以轻松地击败本机C或C ++代码的地方,本机内存分配在它们碰巧存在的任何地方都会被卡住。

C#仍然具有模拟C数组的语法,没有安全保证。 当您发现arrays代码位于程序的关键路径中时,可以使用它们。 这些构造要求您使用unsafe关键字,它们与等效的C代码具有相同的问题:

  • stackalloc关键字可用于从堆栈帧而不是GC堆分配数组。 就像C程序中的本地数组变量一样。 当C#代码中的本地数组产生过多垃圾并且GC集合开始占据程序执行时间时,这是一个后备。
  • fixed关键字可用于声明无需边界检查即可访问的数组。 stackalloc的替代方案,用于需要在方法调用中存活的数组。 当你无法取消索引检查并且分析器告诉你它变得至关重要时,这是一个后备。 这通常只适用于短arrays,即元素访问不是主要成本的类型。

在考虑上述信息的情况下解决您的问题:

哪个类是arr的对象?

从第2个子弹中可以看出,数组有一个专用类型,它是在运行时创建的,无需在程序中明确声明它。 CLR否则保持这样一种错觉:它是一种与元素类型密切相关的类型,就像C#语言语法一样,int数组的数组类型名称是“System.Int32 []”。 然而,它是CLR中的一个独特类型,一个逻辑上派生自System.Array的类,实际上派生自System.SZArrayHelper。 对于这种类型的诡计,我最喜欢的一句话是“庸医就像打鸭子”。

为什么c#的设计者会使用上面的语法?

它是语法糖,非常有效,简短易懂。 如果在.NET 1.0中可以使用generics,它可能看起来有所不同,我有点怀疑它。 值得注意的是,C#对于多维数组(如int[,] )有太多的糖,而对于锯齿状数组(如int[][] )则不够,它们可能会让程序员陷入编写性能不佳的代码。 它们很昂贵,索引表达式需要多次乘法和绑定检查,并且按照对CPU高速缓存非常不友好的顺序访问数组元素太容易了。

c#中的每个变量都是struct或class或enum

C#中的每个变量都有一个类型,该类型是值类型或引用类型。 在某些情况下,所有值类型都被归类为struct ,所有引用类型都被归类为class ,但这并不常见。 如果这就是你的意思,那么“或枚举”是多余的,因为它们是值类型。 如果这不是您的意思,有些情况下您会忽略,例如界面类型。

哪个类是arr的对象?

arrint[]类型的对象。 int[]是一个派生自System.Array的引用类型,但除非您调用所有引用类型类类型,否则将它称为类类型。

为什么c#的设计者会使用上面的语法,为什么他们不使用简单的ClassName ObjectName = new ClassName()和数组

“ClassName”是int[] ,因此你的提议会导致int[] arr = new int[](3); 。 对于从其他语言进入C#的人来说,这更加冗长,看起来并不熟悉,并且实际上并没有设法简化语言:语言仍然需要有特殊的规则来确定[]使用位置。