52

在 C++ 中有很多方法可以编写可编译的代码,但会产生未定义的行为(维基百科)。C#中有类似的东西吗?我们可以用 C# 编写可编译但行为未定义的代码吗?

4

7 回答 7

41

正如其他人所提到的,“不安全”块中的几乎任何东西都可以产生实现定义的行为;滥用不安全块允许您更改构成运行时本身的代码字节,因此所有赌注都没有了。

该部门int.MinValue/-1具有实现定义的行为。

抛出异常并且从不捕获它会导致实现定义的行为——终止进程、启动调试器等等。

在 C# 中还有许多其他情况,我们被迫发出具有实现确定行为的代码。例如,这种情况:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/odious-ambiguous-overloads-part-two

但是,安全、行为良好的 C# 程序具有实现定义行为的情况应该很少见。

于 2009-12-07T16:07:23.917 回答
33

是的!有,即使在安全的情况下!(好吧,至少它的实现定义为未定义)

这是来自 Marek Safar 和 VSadov 在Roslyn 问题中的一个。C# 和 CLI 在bool.

C# 认为只有一种true, 和一种false.

CLI 认为false是一个包含 0 的字节,所有其他值都是true.

这种差异意味着我们可以强制 C# 做一些(勉强)有趣的事情

//non-standard bool
//We're setting a bool's value to a byte value of 5.
var a = new bool[1];
Buffer.SetByte(a, 0, 5);

//non-standard bool
//We're setting a bool's value to a byte value of 10.
var b = new bool[1];
Buffer.SetByte(b, 0, 10);

//Both are true.
Console.WriteLine(a[0]);
Console.WriteLine(b[0]);

//But they are not the same true.
Console.WriteLine(a[0] == b[0]);

上述输出:

true

true

false

有趣的是,调试器不同意(必须以不同的方式评估真相?)

在此处输入图像描述

无论如何,C# 团队似乎得出的结论是(强调添加):

IE 语言将完全不关心非标准布尔值。特定的实现(如在 CIL 上的 MS C# 中)将承认非标准布尔值的存在并将它们的行为指定为未定义

于 2014-10-03T05:28:31.787 回答
12

查看有关未定义行为的维基百科文章,在 C# 中不允许发生未定义行为的情况或引发异常。

但是在 Unsafe 代码中,我相信未定义的行为是可能的,因为它允许您使用指针等。

编辑:看起来我是对的:http: //msdn.microsoft.com/en-us/library/aa664771%28VS.71%29.aspx

在 c# 中有一个未定义行为的示例

于 2009-12-07T15:17:14.737 回答
11

根据 ECMA-334 文件(第 473 页):

不包含任何 unsafe 修饰符的程序不能表现出任何未定义的行为。

这将“实现定义”提升为最坏的情况,请参阅 Eric Lippert 的回答。

于 2009-12-07T22:11:48.233 回答
1

许多子程序的要求可以概括为:

  1. 当给定有效数据时,产生有效输出。

  2. 避免发射核导弹或否定时间和因果律,即使输入无效。

Java 和 .NET 语言的主要设计目标之一是,除非代码使用某些标记为“不安全”的代码,否则通常不需要特别努力来满足上述第二个约束[尽管一些与垃圾收集和Finalize从时间/因果关系的角度来看可能有点奇怪,这些可以被描述为正常因果关系规则的例外,而不是完全撤销它们]。这种情况与 C 中的情况非常不同,在 C 中,多种数据相关错误(例如整数溢出)可能导致编译器以任意方式运行,包括做出避免溢出所必需的任何假设。超现代 C 哲学中鼓励的真正可怕的未定义行为类型在 C# 或“不安全”块之外的其他 .NET 语言中不存在。

于 2015-06-22T20:20:21.470 回答
0

并不是真正的 Wiki 意义上的,但我想我想到的最明显的例子就是简单地编写一些线程代码,但是在任何语言中都是这样。

于 2009-12-07T15:19:40.440 回答
-2

一般来说,我会说不。

在初始化之前使用自动变量。

所有变量都必须初始化。如果没有出现异常。

被零除

抛出异常。

索引数组越界

抛出异常

正如 Aequitarum Custos 指出的那样,您可以使用不安全的代码。再一次,这不是真正的 C#,您明确选择退出 C# 环境。

于 2009-12-07T15:26:19.260 回答