gpt4 book ai didi

c# - 定义精确大小的内存结构

转载 作者:行者123 更新时间:2023-11-30 17:37:14 25 4
gpt4 key购买 nike

我正在做一些内存共享,我将在内存共享区域中使用以下结构...

[StructLayout(LayoutKind.Sequential)]
public struct MySharedMemory
{
//Bools
public bool Flag1;
public bool Flag2;
public bool Flag3;

//DateTimes
public DateTime LastWrite;
public DateTime LastRead;

//Longs
public long SrcSize;

//Strings that are a max of 250 characters
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
public string SrcFile;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
public string DestFile;

//Ints
public int Count;

//An array of strings that are a max of 100 characters
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100, ArraySubType = UnmanagedType.Struct)]
public FileInfo[] FilesToUpdate;
}

我知道上面的所有定义都是正确的,但 DataTime 除外。我只是添加了那些,但我不确定它们是否是固定大小,或者我需要定义一些特殊的东西,就像我为字符串所做的那样。我的问题是,除了数组和字符串之外,还有没有固定大小的任何类型(特别是我的 DateTime 定义是否正确)?

最佳答案

不幸的是 DateTime 是编码(marshal)处理的 weird type(或者,至少,它有一个非常意外的令人惊讶的行为。)

首先,因为它是一个 Auto 结构(这使得它不可 blittable,并且所有的 consequences 都只有一个 long 字段。

您可能会考虑将其包装到一个 blittable 结构中(这不是什么新鲜事,这是编码非 blittable 类型的常用方法):

public struct BlittableDateTime
{
private BlittableDateTime(long ticks)
{
_ticks = ticks;
}

public static implicit operator BlittableDateTime(DateTime value)
{
return new BlittableDateTime(value.Ticks);
}

public static implicit operator DateTime(BlittableDateTime value)
{
return new DateTime(value._ticks);
}

private readonly long _ticks;
}

到目前为止还不错,您可能会想。然而,我们正在转换一个 DateTime(从 1/1/0001 开始的 100 ns 滴答数)到一个 8 字节整数值,在 unmanaged 世界中没有任何等效类型。在非托管世界中,您可能拥有:time_tFILETIMESYSTEMTIMEDATE 和(许多)除 none of them exactly matches granularity and range 之外的 .NET DateTime。更烦人它实际上不是原始 long long 值,因为某些位具有特殊含义,来自源代码:

Bits 63-64: A four-state value that describes the DateTimeKind value of the date time...

你需要一个转换,在这个例子中我使用 FILETIME :

public static implicit operator BlittableDateTime(DateTime value)
{
return new BlittableDateTime(value.ToFileTime());
}

public static implicit operator DateTime(BlittableDateTime value)
{
return DateTime.FromFileTime(value._ticks);
}

编辑:如何使用?我们定义了两个隐式运算符,然后到/从 DateTime 的转换是自动,您不需要在托管代码中直接管理 FILETIME 结构(还要注意构造函数是私有(private)的,所有转换都通过定义的运算符):

BlittableDateTime time1 = DateTime.UtcNow;
DateTime time2 = time1;

但是我们没有为这个类型定义任何比较运算符。如果您不经常这样做,您有两种选择,第一种是转换:

if ((DateTime)time1 == time2) {
// Do something...
}

或者,您可以添加一个返回 ValueDateTime 属性(模仿 Nullable<T> 的用法):

public DateTime Value
{
get { return (DateTime)this; }
}

这样使用:

if (time1.Value == time2) {
// Do something...
}

关于转换的更多说明。请注意,并非所有转换都是可能的,并且 - 在这种情况下 - FILETIME 具有不同的范围。 FILETIME 从 1601 年 1 月 1 日开始,以 100 ns 的粒度跨越 +/- 30,000 年(或多或少),因为它可能是负数。 DateTime 从 1/1/0001 开始,它有效地使用了 62 位信息(262 滴答),但最大值是 9999 年 12 月 31 日。另一个问题:当从 FILETIME 转换回来时,current implementation 不支持负值,然后有效可用范围在 1601 年 1 月 1 日(最小 FILETIME)和 9999 年 12 月 31 日(最大 DateTimeDATE 值)之间。

在处理日期时不要忘记它们(几乎)总是与日历相关联,并且某些日历可能有不同的限制:例如台湾日历从 1/1/0001 开始(即 1/1/1912在公历)和 Um Al Qura 日历结束在 12/29/1450(5/13/2029 在公历)。

关于c# - 定义精确大小的内存结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38331806/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com