C# 中具有未定义行为的代码
在 C++ 中,您可以通过多种方式编写可编译的代码,但会产生未定义行为(维基百科)。 C#中有类似的东西吗?我们可以用 C# 编写可以编译但具有未定义行为的代码吗?
In C++ there are a lot of ways that you can write code that compiles, but yields undefined behavior (Wikipedia). Is there something similar in C#? Can we write code in C# that compiles, but has undefined behavior?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
正如其他人提到的,“不安全”块中的几乎所有内容都可以产生实现定义的行为;滥用不安全块允许您更改构成运行时本身的代码字节,因此所有的赌注都将落空。
除法
int.MinValue/-1
具有实现定义的行为。抛出异常并且从不捕获它会导致实现定义的行为——终止进程、启动调试器等等。
在 C# 中还有许多其他情况,我们被迫发出具有实现确定行为的代码。例如,这种情况:
https: //learn.microsoft.com/en-us/archive/blogs/ericlippert/odious-ambigously-overloads-part-two
但是,安全、行为良好的 C# 程序具有实现定义的行为的情况应该是相当罕见的。
As others have mentioned, pretty much anything in the "unsafe" block can yield implementation-defined behaviour; abuse of unsafe blocks allows you to change the bytes of code that make up the runtime itself, and therefore all bets are off.
The division
int.MinValue/-1
has an implementation-defined behaviour.Throwing an exception and never catching it causes implementation-defined behaviour -- terminate the process, start a debugger, and so on.
There are a number of other situations in C# where we are forced to emit code which has implementation-determined behaviour. For example, this situation:
https://learn.microsoft.com/en-us/archive/blogs/ericlippert/odious-ambiguous-overloads-part-two
However, the situations in which a safe, well-behaved C# program has implementation-defined behaviour should be quite rare.
是的!即使在安全的情况下也是如此! (嗯,至少它的实现定义为未定义)
这是 Marek Safar 和 VSadov 在 Roslyn 问题。C# 和 CLI 在
bool
方面不匹配。C#认为只有一种
true
,和一种false
。CLI 认为
false
是包含 0 的字节,所有其他值都是true
。这种差异意味着我们可以强制 C# 做一些(稍微)有趣的事情:
上面的输出:
true
true
false
有趣的是,调试器不同意(必须以不同的方式评估真实性?)
无论如何,C# 团队似乎得出的结论是(强调):
Yes! There is, even in a safe context! (Well, it's implementation defined to be undefined, at least)
Here's one from Marek Safar and VSadov in the Roslyn issues.There is a mismatch between C# and the CLI in regards to
bool
.C# believes that there is only one kind of
true
, and one kind offalse
.CLI believes that
false
is a byte containing 0, and all other values aretrue
.This discrepancy means we can coerce C# to do
somea (marginally) interestingthingsthing:The above outputs:
true
true
false
Interestingly, the debugger disagrees (must evaluate truth differently?)
Anyways, the conclusion the C# team appears to have come to is (emphasis added):
查看关于未定义行为的维基百科文章,发生未定义行为的情况要么是不允许的或者在 C# 中抛出异常。
然而,在不安全的代码中,我认为未定义的行为是可能的,因为这允许您使用指针等。
编辑:看起来我是对的:http://msdn.microsoft.com/en-us/library/aa664771%28VS.71%29.aspx
有一个C# 中未定义行为的示例
Looking at the Wikipedia article on undefined behaviour, the situations in which undefined behavior happens are either not allowed or throw an exception in C#.
However in Unsafe code, undefined behavior I believe is possible, as that allows you to use pointers etc.
Edit: It looks like I'm right: http://msdn.microsoft.com/en-us/library/aa664771%28VS.71%29.aspx
Has an example of undefined behavior in c#
根据 ECMA-334 文件(第 473 页):
这将“实现定义”提升到最坏的情况,请参阅 Eric Lippert 的回答。
According to the ECMA-334 document (p. 473):
That promotes 'implementation-defined' to the worst case, see Eric Lippert's answer.
许多子程序都有要求,可以概括为:
当给定有效数据时,产生有效输出。
即使输入无效,也不要发射核导弹或否定时间和因果律。
即使输入无效,
Java 和 .NET 语言的主要设计目标之一是,除非代码使用某些标记为“不安全”的内容,否则通常不需要特别努力来满足上述第二个约束[尽管与垃圾收集和 <从时间/因果关系的角度来看,code>Finalize 可能有点奇怪,这些可以被描述为正常因果关系规则的例外,而不是完全撤销它们]。这种情况与 C 中的情况非常不同,在 C 中,许多种与数据相关的错误(例如整数溢出)可能导致编译器以任意方式运行,包括做出任何必要的假设来避免溢出。超现代 C 哲学所鼓励的真正可怕的未定义行为在“不安全”块之外的 C# 或其他 .NET 语言中并不存在。
Many and subprograms have requirements that can be summarized as:
When given valid data, produce valid output.
Refrain from launching nuclear missiles or negating the laws of time and causality, even when given invalid input.
One of the major design goals of Java and .NET languages is that unless code makes use of certain which are marked as "unsafe", no particular effort is generally required to meet the second constraint above [though some behaviors related to garbage collection and
Finalize
can be a little weird from the time/causality standpoint, those can be described as exceptions to normal rules of causality, rather than a total revocation of them]. That situation is very different from the situation in C, where many kinds of data-dependent errors (e.g. integer overflow) may result in compilers behaving in arbitrary fashion including making whatever assumptions would be necessary to avoid overflow. The truly horrible kinds of Undefined Behavior which are encouraged in hypermodern C philosophy do not exist in C# or other .NET languages outside of "unsafe" blocks.不完全是维基意义上的,但我想我想到的最明显的例子就是简单地编写一些线程代码,但在任何语言中都是如此。
Not really in the exactly Wiki sense but I suppose the most obvious example that comes to my mind is simply writing some threaded code, but then it's like that in any language.
C# 规范列出了更多未定义、实现定义和未指定的行为:问题” rel="nofollow noreferrer">https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specation/portability-issues ...这些在规格如下:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/terms-and-definitions
规范不断发展,对于 StackOverflow 的答案来说,列表太长,而且它并不包罗万象。由于规范只有一个术语“未定义行为”(“未定义行为在本规范中仅由‘未定义行为’一词表示。”)谷歌搜索“未定义”站点:https://learn.microsoft.com /en-us/dotnet/csharp/language-reference/" 揭示了一些有趣的花絮:
跨部分类的字段初始化未定义
https://learn.microsoft .com/en-us/dotnet/csharp/语言-参考/语言-规范/类
跨部分类的“文本顺序”是否正式定义?
模式评估顺序未定义
此外,关于列表模式:
https://learn。 microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/list-patterns
同样,如果集合行为不佳,则集合文字行为未定义:
https://learn。 microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/collection-expressions
默认(可为空)。值是实现定义的(不是未定义的)
The C# spec lists a few more undefined, implementation-defined, and unspecified behaviors: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/portability-issues ... these are defined in the spec as follows:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/terms-and-definitions
The spec evolves and the list is too long for a StackOverflow answer, plus it's not all-encompassing. As the spec only has one term for "undefined behavior" ("Undefined behavior is indicated in this specification only by the words ‘undefined behavior.’") googling
"undefined" site:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/"
reveals some interesting tidbits:Field Initialization across Partial Classes is Undefined
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes
Is the "textual order" across partial classes formally defined?
Pattern Evaluation Order is Undefined
Furthermore, regarding list patterns:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/list-patterns
Likewise, Collection Literal behavior is undefined if collections are not well-behaved:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/collection-expressions
default(Nullable).Value is implementation-defined (not undefined)
一般来说我会说不。
在初始化之前使用自动变量。
所有变量都必须初始化。如果没有出现异常。
除以零
抛出异常。
对数组进行索引越界
抛出异常
正如 Aequitarum Custos 指出的那样,您可以使用不安全的代码。话又说回来,这并不是真正的 C#,您明确选择退出 C# 环境。
In general I would say no.
Use Automatic variable before it’s initialized.
All variables must be initialized. If not an exception occurs.
Division by zero
Exception is thrown.
Indexing an array out of bounds
Exception is thrown
As Aequitarum Custos pointed out you can use unsafe code. Then again this isn't really C#, you are explicitly opting out of the C# environment.