字节流与结构、类之间的转换
来源:互联网 发布:淘宝推广广告 编辑:程序博客网 时间:2024/05/29 10:58
准备知识
1. StructLayoutAttribute类
可将该属性应用于类或结构。
通常,公共语言运行库控制类或结构的数据字段在托管内存中的物理布局。如果类或结构需要按某种方式排列,则可以使用 StructLayoutAttribute。如果要将类传递给需要指定布局的非托管代码,则显式控制类布局是重要的。
参数说明
- LayoutKind
LayoutKind 值之一,它指定类或结构的排列方式。
Sequential 对象的成员按照它们在被导出到非托管内存时出现的顺序依次布局。这些成员根据在StructLayoutAttribute.Pack中指定的封装进行布局,并且可以是不连续的。
Explicit 对象的各个成员在非托管内存中的精确位置被显式控制。每个成员必须使用 FieldOffsetAttribute 指示该字段在类型中的位置。
Auto 运行库自动为非托管内存中的对象的成员选择适当的布局。使用此枚举成员定义的对象不能在托管代码的外部公开。尝试这样做将引发异常。
- CharSet
指示在默认情况下应如何将类中的字符串数据字段作为 LPWSTR 或 LPSTR 进行封送处理。
如果 CharSet 字段设置为 CharSet.Unicode,则所有字符串参数在传递到非托管实现之前都转换成 Unicode 字符(LPWSTR)。如果该字段设置为 CharSet.Ansi,则字符串将转换成 ANSI 字符串 (LPSTR)。如果 CharSet 字段设置为CharSet.Auto,则转换与平台相关(在 Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系列上为 Unicode;在 Windows 98 和 Windows Me 上为 ANSI)。
- Pack
控制类或结构的数据字段在内存中的对齐方式。
此字段指示在指定 LayoutKind.Sequential 值时应使用的封装大小。Pack 的值必须为 0、1、2、4、8、16、32、64 或 128。值为 0 则指示封装对齐方式设置为当前平台的默认值。
- Size
指示类或结构的绝对大小。
必须大于或等于所有成员的总和。此字段主要由编译器编写器使用,以指定类或结构的总大小(以字节为单位),而且在扩展由结构占用的内存(用于直接的非托管访问)时,此字段也很有用。例如,在使用未直接在元数据中表示的联合时可使用此字段。
示例
2. MarshalAsAttribute类
可将该属性应用于参数、字段或返回值。
该属性为可选属性,因为每个数据类型都有默认的封送处理行为。仅在可以将给定类型封送到多个类型时需要此属性。例如,可将字符串作为 LPStr、LPWStr、LPTStr 或 BStr 封送到非托管代码。默认情况下,公共语言运行时将字符串参数作为 BStr 封送到 COM 方法。可将 MarshalAsAttribute 属性应用于个别的字段或参数,使该字符串作为 LPStr 而不是 BStr 进行封送。类型库导出程序 (Tlbexp.exe) 将封送处理首选项传递给公共语言运行时。
当用于 COM 互操作或平台调用时,某些参数和返回值将具有不同的默认封送处理行为。默认情况下,运行时将字符串参数(以及值类型中的字段)作为 LPStr 封送到平台调用方法或函数。有关更多信息,请参见 默认封送处理行为。
参数说明
- UnmanagedType
数据将被作为该值封送。
在 System.Runtime.InteropServices.MarshalAsAttribute 中使用 UnmanagedType 枚举,以指定在与非托管代码进行交互的过程中如何对类型进行封送处理。可以使用此枚举对使用简单值类型(I1、I2、I4、I8、R4、R8、U2、U4 和 U8)、.NET Framework 中未提供的非托管类型以及各种杂项类型的代码进行封送处理。
- SizeConst
指示固定长度数组中的元素数,或要导入的字符串中的字符(不是字节)数。
对于 System.Runtime.InteropServices.UnmanagedType 枚举的 ByValArray 和 ByValTStr 成员,此字段是必需的。因为元数据的压缩格式限制为 0x1FFFFFFF,所以 SizeConst 的允许值的范围为(>= 0 且 <= 0x1FFFFFFF)。
3. 不安全代码
为了保持类型安全,默认情况下,C# 不支持指针运算。不过,通过使用 unsafe 关键字,可以定义可使用指针的不安全上下文。
不安全代码具有下列属性:
方法、类型和可被定义为不安全的代码块。
在某些情况下,通过移除数组界限检查,不安全代码可提高应用程序的性能。
当调用需要指针的本机函数时,需要使用不安全代码。
使用不安全代码将引起安全风险和稳定性风险。
在 C# 中,为了编译不安全代码,必须用 /unsafe 编译应用程序。
4. Unsafe
unsafe 关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。
可以在类型或成员的声明中使用 unsafe 修饰符。因此,类型或成员的整个正文范围均被视为不安全上下文。例如,以下是用 unsafe 修饰符声明的方法:
{
// Unsafe context: can use pointers here.
}
不安全上下文的范围从参数列表扩展到方法的结尾,因此指针在以下参数列表中也可以使用:
还可以使用不安全块从而能够使用该块内的不安全代码。例如:
{
// Unsafe context: can use pointers here.
}
若要编译不安全代码,必须指定 /unsafe 编译器选项。无法通过公共语言运行库验证不安全代码。
示例
5. fixed
fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出现在不安全的上下文中。
fixed 语句设置指向托管变量的指针,并在执行该语句期间“固定”此变量。如果没有 fixed 语句,则指向可移动托管变量的指针的作用很小,因为垃圾回收可能不可预知地重定位变量。C# 编译器只允许在 fixed 语句中分配指向托管变量的指针。
可以用数组或字符串的地址初始化指针:
只要指针的类型相同,就可以初始化多个指针:
示例
Fixed 还可用于创建固定大小的缓冲区。
在此结构中,pathName 数组具有固定的大小和位置,因此可用在其他不安全的代码中。
128 个元素的 char 数组的大小为 256 字节。在固定大小的 char 缓冲区中,每个字符始终占用两个字节,而与编码无关。即使将 char 缓冲区封送到具有 CharSet = CharSet.Auto 或 CharSet = CharSet.Ansi 的 API 方法或结构,也是如此。有关更多信息,请参见 CharSet。
另一种常见的固定大小的数组是 bool 数组。bool 数组中的元素的大小始终为一个字节。bool 数组不适合用于创建位数组或位缓冲区。
除了用 stackalloc 创建的内存之外,C# 编译器和公共语言运行时 (CLR) 不执行任何安全缓冲区溢出检查。与所有不安全代码一样,请谨慎使用。
不安全缓冲区与常规数组在以下方面不同:
不安全缓冲区只能用在不安全上下文中。
不安全缓冲区始终是向量(或一维数组)。
数组的声明应包括计数,如 char id[8]。而不能使用 char id[]。
不安全缓冲区只能是不安全上下文中的结构的实例字段。
6. stackalloc
stackalloc 关键字用于不安全的代码上下文中,以便在堆栈上分配内存块。
下面的示例输出斐波那契数列的 100 个数字,其中每个数字都是前两个数字之和。在代码中,大小足够容纳 100 个 int 类型元素的内存块是在堆栈上分配的,而不是在堆上分配的。该块的地址存储在 fib 指针中。此内存不受垃圾回收的制约,因此不必将其钉住(通过使用 fixed)。内存块的生存期受限于定义它的方法的生存期。不能在方法返回之前释放内存。
stackalloc 仅在局部变量的初始值设定项中有效。
由于涉及指针类型,因此 stackalloc 要求不安全上下文。有关更多信息,请参见 不安全代码和指针(C# 编程指南)。
stackalloc 类似于 C 运行时中的 _alloca。
不安全代码的安全性低于安全替代代码。但是,通过使用 stackalloc 可以自动启用公共语言运行时 (CLR) 中的缓冲区溢出检测功能。如果检测到缓冲区溢出,进程将尽快终止,以最大限度地减小执行恶意代码的机会。
字节流与结构、类之间的转换
实际案例
- 字节流与结构、类之间的转换
- 资源与字节流之间的转换
- 结构体与字节流之间转换的一个小例子
- 字节流与字符流之间的转换
- android中bitmap与字节流之间的相互转换
- C#图片字节流与字符串之间的转换
- 对象与字节数组之间的转换工具类
- 字符串与字节之间的转换
- 图像与原始字节之间的转换
- 结构体与字节流的相互转换
- unicode编码宽字节与单字节之间的转换
- 字节数组与结构体的转换
- 字符串,字节数组,流之间的转换
- 网络通信时整型数据与字节之间的转换
- C#下字符串与字节数组之间的相互转换
- Unicode 下宽字节与多字节之间的转换
- Java中字节与无符号数之间的转换
- 多字节与宽字节之间的转换
- Eclipse中SVN的安装步骤(两种)和使用方法
- Android官方在线API网址
- 转载:Java多线程初学者指南(1):线程简介
- 用Android NDK实现四则运算
- 长按Home键进入程序和从桌面进入程序
- 字节流与结构、类之间的转换
- 使用UpdatePanel,在后台调用alert 的解决方法,
- getrlimit Unix系统函数
- vc6 unicode编码
- jquery 弹出层 插件
- JS刷新页面
- 汇编入门学习----第一天(3)【原创】
- LDD3笔记——scull模块加载与卸载函数
- javascript的ajax请求正确写法(兼容多浏览器)