在C#和C ++中声明数组时有什么区别? [英] What is the difference when we declare an array in C# and in C++?

查看:115
本文介绍了在C#和C ++中声明数组时有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我可以假设使用c#语言也可以,但是由于以下事实,我不能.

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

如果我的推论是正确的,我想知道

  1. arr的哪个类?

如果我的推论是错误的

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

解决方案

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

在没有执行保证的情况下,不会初始化元素,运行时不会跟踪数组的大小,没有索引检查.这些功能会以最快的速度启动,否则会引发数十亿个错误和数以万计的恶意软件攻击.缓冲区溢出是C或C ++程序中的一个标准问题,当它破坏内存,随机覆盖其他变量或函数的返回地址时,会产生非常难以诊断的错误.或仅使用数据(即恶意软件攻击媒介)来指挥程序.

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

  • 有专门的IL操作码来创建数组, Type.MakeArrayType()),从GC堆分配存储空间并初始化对象,设置Length属性并初始化数组成员,以便它们都具有它们的默认值(T).
  • 再次访问代码中的数组元素会生成专用的IL操作码,例如 stackalloc 关键字可用于从堆栈中分配数组框架而不是GC堆.就像本地数组变量在C程序中一样.当您的C#代码中的本地数组产生过多的垃圾并且GC集合开始控制程序的执行时间时,这是一个回退.
  • 已修复关键字可用于声明可访问的数组没有边界检查.需要通过方法调用生存的数组的stackalloc的替代方法.当您无法取消索引检查并且探查器告诉您它变得很关键时,这是一个后备方法.通常只有短数组(这种情况下元素访问不是主要成本)才是这种情况.

请牢记以上信息来解决您的问题:

哪个类arr是对象?

从第二个项目符号可以看出,数组具有专用类型,并且它是在运行时创建的,而无需在程序中显式声明.否则,CLR会保持一种错觉,即它是与元素类型密切相关的类型,就像C#语言语法一样,int数组的数组类型名称是"System.Int32 []".但是,它是CLR中不同的类型,该类在逻辑上是从System.Array派生的,而实际上是从System.SZArrayHelper派生的.对于这种类型的恶作剧,我最喜欢的短语是像鸭子一样打字的庸医".

为什么c#的设计师采用上述语法?

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

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

Declaration of array in c++ will allocate a block of memory for three integers.

I can assume the same with language c#, but because of the following facts I can't.

Every variable in c# is struct or class or enum, As Array is a class, arr should be the object of class Array. Intellisense also shows that arr has many member functions same as of functions of class Array, but Array is an abstract class, as we can not instantiate an abstract class, arr can be the object of any other class which might be implementing Array Class

If my deduction is right, I want to know

  1. Which class arr is an object of?

And if my deduction is wrong

  1. I want to know where am I wrong?
  2. Which Class array is an object of?

解决方案

Hard to compare the two, they have very little in common. C++ inherited this array syntax and behavior from the C language. Which was designed with only one goal in mind, only as-fast-as-possible was ever considered. The word "allocate" you use is already a poor mismatch with what happens at runtime, the int[3] syntax merely reserves space. Exactly where that happens depends on the location of the declaration, inside a function it will reserve space on the stack frame, outside it will reserve space in the data section.

With no execution guarantees, the elements are not initialized, the runtime doesn't keep track of the size of the array, there is no index checking. As fast as possible, features that otherwise launched billions of bugs and tens of thousands of malware attacks. A buffer overflow is a standard problem in a C or C++ program, producing very hard to diagnose bugs when it corrupts memory, randomly overwriting other variables or the return address of a function. Or commandeer a program simply with data, the malware attack vector.

Not the C# way of course. Array types are reference types in the .NET Framework, their storage is always allocated from the GC heap. The fast gen#0 heap if the array is small (less than 85KB), from the Large Object Heap otherwise. There is lots and lots of glue in the jitter and the CLR to make them still as fast as possible, in spite of their guarantees:

  • there is dedicated IL opcode to create an array, Opcodes.NewArr, the jitter translates it to a direct call into the CLR.
  • this helper function dynamically creates the array type if it doesn't exist yet (compare to Type.MakeArrayType()), allocates the storage from the GC heap and initializes the object, setting the Length property and initializing the array members so they all have their default(T) value.
  • accessing the elements of the array in your code again produces dedicated IL opcodes, like Opcodes.LdElem. The jitter translates them into machine code instructions that check the array bounds and accesses the array element.
  • other array members produce direct calls to the internal SZArrayHelper class, optimized to produce fast-as-possible code for one-dimensional arrays.
  • the code optimizer in the jitter looks for opportunities to eliminate the array bound checks, possible when it can see from the code that the index expression cannot be out-of-bounds. This is often possible, particularly when you use foreach or write a for(;;) loop that uses the array's Length property, array access is then just as fast as the equivalent in C.
  • the garbage collector has built-in knowledge of arrays, it rearranges array elements of a reference type when it compacts the heap so they can be sequentially accessed in code that iterates the array. Very, very important on modern processors that depend on the CPU caches to make memory access fast. This is where managed code can beat native C or C++ code handily, native memory allocations are stuck wherever they happen to exist.

C# still has syntax to emulate C arrays, without the safety guarantees. You can use them when you found that the array code is in the critical path for your program. These constructs require you to use the unsafe keyword, they have the same problems as the equivalent C code:

  • the stackalloc keyword is available to allocate an array from the stack frame instead of the GC heap. Just like a local array variable does in a C program. It is a fallback when the local arrays in your C# code produce too much garbage and GC collections start to dominate your program's execution time.
  • the fixed keyword is available to declare arrays that can be accessed without bounds checking. The alternative for stackalloc for arrays that need to survive the method call. It is a fallback when you can't get the index checking eliminated and the profiler tells you that it becomes critical. This is generally only the case for short arrays, the kind where the element access isn't the dominant cost.

Addressing your questions with the above info in mind:

Which class arr is an object of?

As you can tell from the 2nd bullet, an array has a dedicated type and it is created on the fly without you explicitly declaring it in your program. The CLR otherwise maintains the illusion that it is a type strongly correlated to the element type, like the C# language syntax does, the name of the array type for an array of ints is "System.Int32[]". It is however a distinct type in the CLR, a class that logically derives from System.Array and practically derives from System.SZArrayHelper. My favorite phrase for such type shenanigans is "quacks like a duck-typing".

Why the designers of c# go with the above syntax?

It is syntax sugar, pretty effective at being short and understandable. It might have looked different if generics would have been available at .NET 1.0, I kind of doubt it. Notable as well is that C# has a bit too much sugar for multi-dimensional arrays (like int[,]) and not enough for jagged arrays (like int[][]), they can lull a programmer into writing poorly performing code. They are expensive, index expressions require multiple multiplications and bound checks and it is way too easy to access the array elements in an order that is very unfriendly to the CPU caches.

这篇关于在C#和C ++中声明数组时有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆