【发布时间】:2019-03-08 18:19:25
【问题描述】:
假设我使用MemoryMarshal.CreateSpan 来访问本地值类型的字节,例如以下(不是很有用)代码:
using System;
using System.Runtime.InteropServices;
// namespace and class boilerplate go here
private static void Main()
{
int value = 0;
Span<byte> valueBytes = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref value, 1));
var random = new Random();
while (value >= 0) // the check in question
{
random.NextBytes(valueBytes);
Console.WriteLine(value);
}
}
虽然此代码按预期工作,但如果变量value 未在循环中修改,除非通过 @ 987654325@跨度?我可以依靠阅读value 给我写到valueBytes 的内容,或者这是否容易被重新排序?还是我只是因为最近涉足了一点 C++ 而变得偏执?
(注意我知道还有其他方法可以达到上述代码的预期效果,这不是关于如何获得全范围32位随机整数的问题或关于某些更大应用程序的XY问题我正在尝试将此代码放入其中,不存在这样更大的应用程序)
【问题讨论】:
-
好问题!我想它也可以扩展到指令重新排序可能会或可能不会与这种情况混淆(比如通过跨度修改 int 值,然后访问 int 值。是否保证 C# 编译器或 JITer 会检测到这种情况并防止跨度写访问在值变量的访问之后被重新排序?)
-
@elgonzo - 很好,我已经更新了问题以包含它。
-
听起来你被 C 和 C++ 中的类型双关语规则所困扰。他们确实可怕地滥用了它。 C# 确实记录了原始规则的意图,从较小的类型转换为具有较大对齐要求的较大类型是未定义的。这只是硬处理器行为,在 RISC 时代更为重要。滥用规则停止检查指针别名,真正的邪恶行为,这不是问题。标准的第 23.5.1 节明确允许这种转换。请注意,与您在此处所做的一样,字节级别的寻址也是在 C 和 C++ 中定义的。
标签: c# memory compilation