为什么 C++ 需要“管理”语言修改吗?
为什么不能编写一个编译器来管理 C++ 代码中需要管理的内容(即使其“与 CLR 兼容”)?
也许需要一些妥协,比如在某些情况下禁止 void 指针等。但是所有这些额外的关键字等等。这些添加必须解决的问题是什么?
我对某些方面以及可能难以解决的问题有自己的想法,但如果有一个良好可靠的解释,将不胜感激!
Why can't a compiler be written that manages what needs to be managed in C++ code (i.e. to make it "CLR compatible")?
Maybe with some compromise, like prohibiting void pointers in some situations etc. But all these extra keywords etc. What's the problem that has to be solved by these additions?
I have my thoughts about some aspects and what might be hard to solve, but a good solid explanation would be highly appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
到目前为止,我不得不不同意这些答案。
要理解的主要问题是 C++ 编译器创建的代码适合非常愚蠢的环境。 即使是现代的 CPU 也不知道虚拟功能,见鬼,甚至连功能都是一个延伸。 例如,CPU 实际上并不关心用于展开堆栈的异常处理代码是否位于任何函数之外。 CPU 处理指令序列,包括跳转和返回。 就 CPU 而言,函数当然没有名称。
因此,支持函数概念所需的所有内容都由编译器放置在那里。 例如,vtable 只是具有正确大小的数组,从 CPU 的角度来看具有正确的值。
__func__
最终作为字符串表中的一个字节序列,其中最后一个是 00。现在,没有任何内容表明目标环境必须是哑的。 你绝对可以瞄准 JVM。 同样,编译器必须填写本机未提供的内容。 没有原始内存? 然后分配一个大字节数组并使用它来代替。 没有原始指针? 只需在该大字节数组中使用整数索引即可。
主要问题是 C++ 程序在宿主环境中看起来完全无法识别。 JVM 并不傻,它知道函数,但它希望它们是类成员。 它不希望他们的名称中包含
<
和>
。 你可以绕过这个,但你最终得到的基本上是名称修改。 与当今的名称修饰不同,这种名称修饰并非针对 C 链接器,而是针对智能环境。 因此,它的反射引擎可能会确信存在一个带有成员函数__namespace_std__for_each__arguments_int_pointer_int_pointer_function_address
的类c__plus__plus
,这仍然是一个很好的例子。 我不想知道如果您有一个std::map
字符串来反向迭代器会发生什么。一般来说,相反的方法实际上要容易得多。 几乎所有其他语言的抽象都可以在 C++ 中消除。 垃圾收集? 如今,C++ 中已经允许这样做,因此您甚至可以支持
void*
。我还没有解决的一件事是性能。 在大字节数组中模拟原始内存? 这不会很快,特别是如果你把双打放进去的话。 你可以使用很多技巧来加快速度,但是要付出什么代价呢? 您可能不会获得商业上可行的产品。 事实上,您可能会使用一种将 C++ 最糟糕的部分(许多不寻常的依赖于实现的行为)与 VM 最糟糕的部分(速度慢)结合起来的语言。
I'd have to disagree with the answers so far.
The main problem to understand is that a C++ compiler creates code which is suitable for a very dumb environment. Even a modern CPU does not know about virtual functions, hell, even functions are a stretch. A CPU really doesn't care that exception handling code to unwind the stack is outside any function, for instance. CPU's deal in instruction sequences, with jumps and returns. Functions certainly do not have names as far as the CPU is concerned.
Hence, everything that's needed to support the concept of a function is put there by the compiler. E.g. vtables are just arrays of the right size, with the right values from the CPUs viewpoint.
__func__
ends up as a sequence of bytes in the string table, the last one of which is 00.Now, there's nothing that says the target environment has to be dumb. You could definitely target the JVM. Again, the compiler has to fill in what's not natively offered. No raw memory? Then allocate a big byte array and use it instead. No raw pointers? Just use integer indices into that big byte array.
The main problem is that the C++ program looks quite unrecognizable from the hosting environment. The JVM isn't dumb, it knows about functions, but it expects them to be class members. It doesn't expect them to have
<
and>
in their name. You can circumvent this, but what you end up with is basically name mangling. And unlike name mangling today, this kind of name mangling isn't intended for C linkers but for smart environments. So, its reflection engine may become convinced that there is a classc__plus__plus
with member function__namespace_std__for_each__arguments_int_pointer_int_pointer_function_address
, and that's still a nice example. I don't want to know what happens if you have astd::map
of strings to reverse iterators.The other way around is actually a lot easier, in general. Pretty much all abstractions of other languages can be massaged away in C++. Garbage collection? That's already allowed in C++ today, so you could support that even for
void*
.One thing I didn't address yet is performance. Emulating raw memory in a big byte array? That's not going to be fast, especially if you put doubles in them. You can play a whole lot of tricks to make it faster, but at which price? You're probably not going to get a commercially viable product. In fact, you might up with a language that combines the worst parts of C++ (lots of unusual implementation-dependent behavior) with the worst parts of a VM (slow).
现有的正确代码,即根据 C++ 标准编写的代码,不得无意中改变其行为。
Existing correct code, i.e. code written according to the C++ standard, must not change its behaviour inadvertently.
C++/CLI 主要是作为托管代码和非托管代码之间的粘合剂。 因此,您需要能够混合托管和非托管概念。 您需要能够在同一代码中分配托管和非托管对象,因此无法绕过单独的关键字。
Well C++/CLI is mostly meant to be a glue between managed and unmanaged code. As such you need to have the ability to mix mangaged an unmanaged concepts. You need to be able to allocate managed and unmanged objects in the same code, so there is no way around separate key words.
为什么不能编译针对 CLR 的本机 C++ 代码?
是的,你猜对了,妥协太多,那就没用了。 我只想举三个例子...
1.) 模板:C++ 支持它们,CLR 不支持(泛型不同)。
所以你不能在你的代码中使用STL、boost等。
2.) 多重继承:C++ 支持,CLI 不支持。
您甚至无法使用标准 iostream 类及其派生类(如 stringstream、fstream),它们继承自 istream 和 ostream。
几乎没有任何代码可以编译,您甚至无法实现标准库。
3.) 垃圾收集:
大多数 C++ 应用程序手动管理内存(使用智能指针等),CLR 具有自动内存管理功能。
因此,C++ 风格的“new”和“delete”将与“gcnew”不兼容,使得现有的 C++ 代码对于这个新编译器毫无用处。
如果您必须根除所有重要功能,甚至是标准库,并且现有代码无法编译……那么还有什么意义呢?
Why can't you compile native C++ code targetting the CLR?
Yes, you guessed it right, there would be too many compromises, that would make it useless. I'd like to name just three examples...
1.) Templates: C++ supports them, the CLR doesn't (generics are different).
So you couldn't use the STL, boost etc. in your code.
2.) Multiple inheritance: supported in C++, not in CLI.
You couldn't even use the standard iostream class and derivatives (like stringstream, fstream), which inherit both from istream and ostream.
Almost none of the code out there would compile, you couldn't even implement the standard library.
3.) Garbage collection:
Most C++ apps manage their memory manually (using smart pointers etc.), the CLR has automatic memory management.
Thus the C++ style "new" and "delete" would be incompatible with "gcnew", making existing C++ code useless for this new compiler.
If you'd have to root out all the important features, even the standard library, and no existing code would compile... then what's the point?
首先,“简单 C++”和“托管 C++”之间的区别是有意为之的,因为 MC++ 的目的之一是在现有 C++ 代码和 CLR 之间提供桥梁。
其次,有太多 C++ 功能不适合 CLR 模型。 多重继承、模板、指针算术……如果没有明确的界限,程序员注定会在编译和运行时面临神秘的错误。
First of all, the distinction between "simple C++" and "managed C++" was intentional, because one of the MC++ purposes was to provide a bridge between existing C++ code and CLR.
Next, there's just too many C++ features that don't fit into CLR model. Multiple inheritance, templates, pointer arithmetics... Without drawing a clear line the programmers would be doomed to face cryptic errors, both at compile- and runtime.
我认为这是因为将托管代码功能添加到 C++ 中会使 C++ 变慢并且编译器更复杂。 如此之多以至于 C++ 将失去它最初的设计目的。 C++ 的优点之一是它是一种很好用的语言,它足够低级,但又具有一定的可移植性。 也许这就是 C++ 标准委员会计划让它保持这种状态的原因。 无论如何,我不认为 C++ 可以完全“托管”,因为这意味着用 C++ 编写的程序需要 VM 来执行。 如果是这样,为什么不直接使用 C++/CLI 呢?
I think this is because adding managed code features into C++ would made C++ slower and the compiler more complex. So much so that C++ would lose what it's designed for in the first place. One of the nice things of C++ is that it's a nice language to work with, it's low-level enough and yet somewhat portable. And probably that's what the C++ Standard Committee plans to made it stay that way. Anyway I do not think C++ can ever be fully "managed", because that would mean programs written in C++ needs a VM to execute. If that's the case, why not just use C++/CLI?
Qt 框架 几乎可以做到这一点。 即它有智能指针,当它们指向的对象被销毁时,它们会自动设置为空。
经过 moc(元对象编译器)解析后,它仍然是本机 C++。
Qt framework does almost that. I.e. it has smart pointers, that automatically set to null, when the object that they point to is destroyed.
And still it's a native C++, after parsed by moc(meta object compiler).
是的,我认为 C++ 可以变得托管。 但是,.NET 需要针对 C++ 进行重写,而不是偏向 BASIC。 在同一个屋檐下拥有多种语言。 某些功能必须被删除。 在 VB.NET 和 C++.NET 之间进行选择,最终选择了 VB.NET。 有趣的是,我听说 C# 比 VB.NET 更流行(尽管我两者都不用!)。
Yes, I suppose C++ could become managed. But then .NET would need to be rewritten for C++ and not with a bias towards BASIC. With having many languages all under the same roof. Certain features have got to go. It was a choice between VB.NET or C++.NET, and VB.NET was chosen. Funny thing I hear is that C# is more popular than VB.NET (although I use neither!).
.NET CLR 要求对托管对象的引用不能存在于运行时不知道的任何地方,除非对象被固定; 良好的性能要求尽可能少地固定对象。 由于 .NET CLR 无法理解 C++ 中可用的所有数据结构,因此不得在此类结构中保留对托管对象的引用。 可以让“普通”C++ 代码与 .NET 代码交互,而无需对 C++ 语言进行任何更改,但 C++ 代码可以保留对任何 .NET 对象的任何类型“引用”的唯一方法是拥有一些.NET 端的代码为每个对象分配某种类型的句柄,并保留与句柄关联的对象的静态表。 想要操作对象的 C++ 代码必须要求 .NET 包装器对句柄标识的对象执行某些操作。 添加新语法使编译器能够识别 .NET 框架需要了解的对象类型,并对它们实施必要的限制。
The .NET CLR requires that no reference to a managed object can ever exist anyplace the run-time doesn't know about except while the object is pinned; good performance requires that objects be pinned as little as possible. Since the .NET CLR cannot understand all of the data structures that are usable within C++, it's imperative that no references to managed objects ever be persisted in such structures. It would be possible to have "ordinary" C++ code interact with .NET code without any changes to the C++ language, but the only way the C++ code could keep any sort of "reference" to any .NET objects would be to have a some code on the .NET side assign each object a handle of some sort, and keep a static table of the objects associated with the handles. C++ code which wanted to manipulate the objects would then have to ask the .NET wrapper to perform some operation upon the object identified by a handle. Adding the new syntax makes it possible for the compiler to identify the kinds of objects the .NET framework will need to know about, and enforce the necessary restrictions upon them.
首先要考虑的是
一切让
c++
“快”的东西都会消失。C++ 中的完整垃圾收集系统几乎是不可能的。
因为
c++
你几乎可以在代码中的任何地方使用指针。如果不直接将运行时类型信息内置到
语言系统本身。
您可以利用真正的本机性能。
模板将会消失。 真正的指针将会消失。
直接访问内存已经不复存在。
必须强制执行的事项清单
first thing to consider is
every thing that makes
c++
"fast" will disappear.a full garbage collection system in c++ is next to impossible.
because
c++
you can have pointer nearly anywhere in the code.runtime type information becomes costly if not directly built into the
langauge system it self.
you can take advantage of true native performance.
template will dissappear. true pointers will dissapear.
direct access to memory is gone.
list of things that would have to be enforced
我同意5锤! 如果我离开 Java 和其他托管语言,那不是没有意义的:那就是对计算机有完全的控制,自己访问内存管理内存,控制计算机如何运行我的代码,与 C 库(例如 Lua)集成。
如果我失去了这种灵活性,那么我就会离开 C++ 并回退到 C,如果 C 也变得托管,那么我就会转向汇编程序。
对于所有游戏平台/复杂程序来说,托管语言是最糟糕的语言,因为它们将您限制在某种沙箱中,无法直接访问硬件,并且比编译语言慢得多。
C++ 的主要目的始终是性能。 它是大型游戏的最佳语言之一。 如果没有这种语言表演,很多游戏就不会存在!
I agree with 5hammer ! If I left Java and other managed languages that's not for nothing : that's to have FULL control over the computer, access memory manage memory myself, have control over how the computer will run my code, integrate with C libraries (such as Lua).
If I loose that flexibility, then I would just leave C++ and fall back to C, and if C becomes managed too, then I would go to assembler.
Managed languages are the worst ones ever for all gaming platforms/complex programs as they are bounding you in some kine of sandbox with no direct access to the hardware, and are much slower than compiled languages.
The main purpose of C++ had always been Performence. It's one of the best language for big Games. And without this language performences a lot of games would not exist !