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

Rat*_*kur 9 c# arrays

int[] arr = new int[3]; // C#
int arr[3]; //C++
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  1. 哪个类是arr的对象?

如果我的演绎错了

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

Han*_*ant 13

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

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

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

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

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

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

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

哪个类是arr的对象?

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

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

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

  • +1专注于两个非常_different_和保证在C#和C++中非常不同的事实.我认为这个答案比hvd的其他答案要好得多. (4认同)

小智 10

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

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

哪个类是arr的对象?

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

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

"ClassName"是int[],因此您的提案将导致int[] arr = new int[](3);.对于从其他语言进入C#的人来说,这看起来更加冗长,并不熟悉,并且实际上并没有设法简化语言:语言需要针对何处[]可能使用的特殊规则.