GVKun编程网logo

Swift 5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes(...)(swift不提供什么服务)

11

以上就是给各位分享Swift5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes,其中也会对...进行解释,同时本文还将给你拓展C#+无unsafe的非托管大数组

以上就是给各位分享Swift 5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes,其中也会对...进行解释,同时本文还将给你拓展C#+无unsafe的非托管大数组示例详解(large unmanaged array in c# without ‘unsafe’ keyword)、go语言源码阅读unsafe包和unsafe.Pointer以及go指针运算、ios – UnsafePointer不再适用于swift 3、ios – 在swift中不能在不同大小的类型之间使用unsafeBitCast等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

Swift 5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes(...)(swift不提供什么服务)

Swift 5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes(...)(swift不提供什么服务)

我以前在Swift 4.2中使用以下代码来生成ID:

public static func generateId() throws -> UInt32 {    let data: Data = try random(bytes: 4)    let value: UInt32 = data.withUnsafeBytes { $0.pointee } // deprecated warning!    return value // + some other stuff }

withUnsafeBytes在Swift 5.0上已弃用。我该如何解决?

答案1

小编典典

在Swift
5中,使用(untyped)调用闭包的withUnsafeBytes()方法,您可以从原始内存中获取值:Data``UnsafeRawBufferPointerload()

let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }

(在Swift论坛中比较如何以明确定义的方式使用Data.withUnsafeBytes?)。请注意,这要求内存在4字节边界上_对齐_

另请注意,从Swift 4.2开始,您可以使用新RandomAPI轻松创建一个随机的32位整数:

let randomId = UInt32.random(in: .min ... .max)

C#+无unsafe的非托管大数组示例详解(large unmanaged array in c# without ‘unsafe’ keyword)

C#+无unsafe的非托管大数组示例详解(large unmanaged array in c# without ‘unsafe’ keyword)

C#申请一个大数组(Use a large array in C#)

在C#里,有时候我需要能够申请一个很大的数组、使用之、然后立即释放其占用的内存。

Sometimes I need to allocate a large array, use it and then release its memory space immediately.

由于在C#里提供的 int[] array = new int[1000000]; 这样的数组,其内存释放很难由程序员完全控制,在申请一个大数组后,程序可能会变得很慢。

If I use something like  int[] array = new int[1000000]; , it will be difficult to release its memory space by programmer and the app probably runs slower and slower.

特别是在C#+OpenGL编程中,我在使用VAO/VBO时十分需要设计一个非托管的数组,比如在glBufferData时我希望可以使用下面的glBufferData:

Specially in C#+OpenGL routines when I''m using VAO/VBO, I need an unmanaged array for glBufferData:

/// <summary>
 /// 设置当前VBO的数据。
 /// </summary>
 /// <param name="target"></param>
 /// <param name="data"></param>
 /// <param name="usage"></param>
 public static void glBufferData(uint target, UnmanagedArrayBase data, uint usage)
 {
 GetDelegateFor<glBufferData>()((uint)target,
 data.ByteLength, // 使用非托管数组
 data.Header, // 使用非托管数组
 (uint)usage);
 }
 // ...
 // glBufferData的声明
 private delegate void glBufferData(uint target, int size, IntPtr data, uint usage);

而在指定VBO的数据时,可能是float、vec3等等类型:

And the content in VBO can be float, vec3 and any other structs.

/// <summary>
 /// 金字塔的posotion array.
 /// </summary>
 static vec3[] positions = new vec3[]
 {
 new vec3(0.0f, 1.0f, 0.0f),
 new vec3(-1.0f, -1.0f, 1.0f),
 // ...
 new vec3(-1.0f, -1.0f, 1.0f),
 };
// Create a vertex buffer for the vertex data.
 {
 uint[] ids = new uint[1];
 GL.GenBuffers(1, ids);
 GL.BindBuffer(GL.GL_ARRAY_BUFFER, ids[0]);
 // 使用vec3作为泛型的非托管数组的参数
 UnmanagedArray<vec3> positionArray = new UnmanagedArray<vec3>(positions.Length);
 for (int i = 0; i < positions.Length; i++)
 {
  // 使用this[i]这样的索引方式来读写非托管数组的元素
  positionArray[i] = positions[i];
 }
 GL.BufferData(BufferDataTarget.ArrayBuffer, positionArray, BufferDataUsage.StaticDraw);
 GL.VertexAttribPointer(positionLocation, 3, GL.GL_FLOAT, false, 0, IntPtr.Zero);
 GL.EnableVertexAttribArray(positionLocation);
 }

UnmanagedArray<T>

所以我设计了这样一个非托管的数组类型:无unsafe,可接收任何struct类型作为泛型参数,可随时释放内存。

So I designed this UnmangedArray<T> : no ''unsafe'' keyword, takes any struct as generic parameter, can be released anytime you want.

1 /// <summary>
 2 /// 元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct的非托管数组。
 3 /// <para>不能使用enum类型作为T。</para>
 4 /// </summary>
 5 /// <typeparam name="T">sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct, 不能使用enum类型作为T。</typeparam>
 6 public class UnmanagedArray<T> : UnmanagedArrayBase where T : struct
 7 {
 8 
 9 /// <summary>
 10 ///元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct的非托管数组。 
 11 /// </summary>
 12 /// <param name="count"></param>
 13 [MethodImpl(MethodImplOptions.Synchronized)]
 14 public UnmanagedArray(int count)
 15 : base(count, Marshal.SizeOf(typeof(T)))
 16 {
 17 }
 18 
 19 /// <summary>
 20 /// 获取或设置索引为<paramref name="index"/>的元素。
 21 /// </summary>
 22 /// <param name="index"></param>
 23 /// <returns></returns>
 24 public T this[int index]
 25 {
 26 get
 27 {
 28  if (index < 0 || index >= this.Count)
 29  throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 30 
 31  var pItem = this.Header + (index * elementSize);
 32  //var obj = Marshal.PtrToStructure(pItem, typeof(T));
 33  //T result = (T)obj;
 34  T result = Marshal.PtrToStructure<T>(pItem);// works in .net 4.5.1
 35  return result;
 36 }
 37 set
 38 {
 39  if (index < 0 || index >= this.Count)
 40  throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 41  
 42  var pItem = this.Header + (index * elementSize);
 43  //Marshal.StructureToPtr(value, pItem, true);
 44  Marshal.StructureToPtr<T>(value, pItem, true);// works in .net 4.5.1
 45 }
 46 }
 47 
 48 /// <summary>
 49 /// 按索引顺序依次获取各个元素。
 50 /// </summary>
 51 /// <returns></returns>
 52 public IEnumerable<T> GetElements()
 53 {
 54 if (!this.disposed)
 55 {
 56  for (int i = 0; i < this.Count; i++)
 57  {
 58  yield return this[i];
 59  }
 60 }
 61 }
 62 }
 63 
 64 /// <summary>
 65 /// 非托管数组的基类。
 66 /// </summary>
 67 public abstract class UnmanagedArrayBase : IDisposable
 68 {
 69 
 70 /// <summary>
 71 /// 数组指针。
 72 /// </summary>
 73 public IntPtr Header { get; private set; }
 74 
 75 /// <summary>
 76 /// 元素数目。
 77 /// </summary>
 78 public int Count { get; private set; }
 79 
 80 /// <summary>
 81 /// 单个元素的字节数。
 82 /// </summary>
 83 protected int elementSize;
 84 
 85 /// <summary>
 86 /// 申请到的字节数。(元素数目 * 单个元素的字节数)。
 87 /// </summary>
 88 public int ByteLength
 89 {
 90 get { return this.Count * this.elementSize; }
 91 }
 92 
 93 
 94 /// <summary>
 95 /// 非托管数组。
 96 /// </summary>
 97 /// <param name="elementCount">元素数目。</param>
 98 /// <param name="elementSize">单个元素的字节数。</param>
 99 [MethodImpl(MethodImplOptions.Synchronized)]
100 protected UnmanagedArrayBase(int elementCount, int elementSize)
101 {
102 this.Count = elementCount;
103 this.elementSize = elementSize;
104 
105 int memSize = elementCount * elementSize;
106 this.Header = Marshal.AllocHGlobal(memSize);
107 
108 allocatedArrays.Add(this);
109 }
110 
111 private static readonly List<IDisposable> allocatedArrays = new List<IDisposable>();
112 
113 /// <summary>
114 /// 立即释放所有<see cref="UnmanagedArray"/>。
115 /// </summary>
116 [MethodImpl(MethodImplOptions.Synchronized)]
117 public static void FreeAll()
118 {
119 foreach (var item in allocatedArrays)
120 {
121  item.Dispose();
122 }
123 allocatedArrays.Clear();
124 }
125 
126 ~UnmanagedArrayBase()
127 {
128 Dispose();
129 }
130 
131 #region IDisposable Members
132 
133 /// <summary>
134 /// Internal variable which checks if Dispose has already been called
135 /// </summary>
136 protected Boolean disposed;
137 
138 /// <summary>
139 /// Releases unmanaged and - optionally - managed resources
140 /// </summary>
141 /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
142 protected void Dispose(Boolean disposing)
143 {
144 if (disposed)
145 {
146  return;
147 }
148 
149 if (disposing)
150 {
151  //Managed cleanup code here, while managed refs still valid
152 }
153 //Unmanaged cleanup code here
154 IntPtr ptr = this.Header;
155 
156 if (ptr != IntPtr.Zero)
157 {
158  this.Count = 0;
159  this.Header = IntPtr.Zero;
160  Marshal.FreeHGlobal(ptr);
161 }
162 
163 disposed = true;
164 }
165 
166 /// <summary>
167 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
168 /// </summary>
169 public void Dispose()
170 {
171 this.Dispose(true);
172 GC.SuppressFinalize(this);
173 }
174 
175 #endregion
176  
177 }

UnmanagedArray

如何使用(How to use)

UnmanagedArray<T>使用方式十分简单,就像一个普通的数组一样:

Using UnamangedAray<T> is just like a normal array(int[], vec3[], etc.):

internal static void TypicalScene()
 {
 const int count = 100;

 // 测试float类型
 var floatArray = new UnmanagedArray<float>(count);
 for (int i = 0; i < count; i++)
 {
 floatArray[i] = i;
 }
 for (int i = 0; i < count; i++)
 {
 var item = floatArray[i];
 if (item != i)
 { throw new Exception(); }
 }

 // 测试int类型
 var intArray = new UnmanagedArray<int>(count);
 for (int i = 0; i < count; i++)
 {
 intArray[i] = i;
 }
 for (int i = 0; i < count; i++)
 {
 var item = intArray[i];
 if (item != i)
 { throw new Exception(); }
 }

 // 测试bool类型
 var boolArray = new UnmanagedArray<bool>(count);
 for (int i = 0; i < count; i++)
 {
 boolArray[i] = i % 2 == 0;
 }
 for (int i = 0; i < count; i++)
 {
 var item = boolArray[i];
 if (item != (i % 2 == 0))
 { throw new Exception(); }
 }

 // 测试vec3类型
 var vec3Array = new UnmanagedArray<vec3>(count);
 for (int i = 0; i < count; i++)
 {
 vec3Array[i] = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
 }
 for (int i = 0; i < count; i++)
 {
 var item = vec3Array[i];
 var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
 if (item.x != old.x || item.y != old.y || item.z != old.z)
 { throw new Exception(); }
 }

 // 测试foreach
 foreach (var item in vec3Array.GetElements())
 {
 Console.WriteLine(item);
 }

 // 释放此数组占用的内存,这之后就不能再使用vec3Array了。
 vec3Array.Dispose();

 // 立即释放所有非托管数组占用的内存,这之后就不能再使用上面申请的数组了。
 UnmanagedArrayBase.FreeAll();
 }

快速读写UnmanagedArray<T>

UnmanagedArrayHelper

由于很多时候需要申请和使用很大的UnmanagedArray<T>,直接使用this[index]索引方式速度会偏慢,所以我添加了几个辅助方法,专门解决快速读写UnmanagedArray<T>的问题。

public static class UnmanagedArrayHelper
 {
 ///// <summary>
 ///// 错误 1 无法获取托管类型(“T”)的地址和大小,或无法声明指向它的指针
 ///// </summary>
 ///// <typeparam name="T"></typeparam>
 ///// <param name="array"></param>
 ///// <returns></returns>
 //public static unsafe T* FirstElement<T>(this UnmanagedArray<T> array) where T : struct
 //{
 // var header = (void*)array.Header;
 // return (T*)header;
 //}

 /// <summary>
 /// 获取非托管数组的第一个元素的地址。
 /// </summary>
 /// <param name="array"></param>
 /// <returns></returns>
 public static unsafe void* FirstElement(this UnmanagedArrayBase array)
 {
 var header = (void*)array.Header;

 return header;
 }

 public static unsafe void* LastElement(this UnmanagedArrayBase array)
 {
 var last = (void*)(array.Header + (array.ByteLength - array.ByteLength / array.Length));

 return last;
 }

 /// <summary>
 /// 获取非托管数组的最后一个元素的地址再向后一个单位的地址。
 /// </summary>
 /// <param name="array"></param>
 /// <returns></returns>
 public static unsafe void* TailAddress(this UnmanagedArrayBase array)
 {
 var tail = (void*)(array.Header + array.ByteLength);

 return tail;
 }
 }

如何使用

这个类型实现了3个扩展方法,可以获取UnmanagedArray<T>的第一个元素的位置、最后一个元素的位置、最后一个元素+1的位置。用这种unsafe的方法可以实现C语言一样的读写速度。

下面是一个例子。用unsafe的方式读写UnmanagedArray<T>,速度比this[index]方式快10到70倍。

public static void TypicalScene()
 {
 int length = 1000000;
 UnmanagedArray<int> array = new UnmanagedArray<int>(length);
 UnmanagedArray<int> array2 = new UnmanagedArray<int>(length);

 long tick = DateTime.Now.Ticks;
 for (int i = 0; i < length; i++)
 {
 array[i] = i;
 }
 long totalTicks = DateTime.Now.Ticks - tick;

 tick = DateTime.Now.Ticks;
 unsafe
 {
 int* header = (int*)array2.FirstElement();
 int* last = (int*)array2.LastElement();
 int* tailAddress = (int*)array2.TailAddress();
 int value = 0;
 for (int* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++)
 {
  *ptr = value++;
 }
 }
 long totalTicks2 = DateTime.Now.Ticks - tick;
 Console.WriteLine("ticks: {0}, {1}", totalTicks, totalTicks2);// unsafe method works faster.

 for (int i = 0; i < length; i++)
 {
 if (array[i] != i)
 {
  Console.WriteLine("something wrong here");
 }
 if (array2[i] != i)
 {
  Console.WriteLine("something wrong here");
 }
 }

 array.Dispose();
 array2.Dispose();
 }
unsafe
 {
  vec3* header = (vec3*)vec3Array.FirstElement();
  vec3* last = (vec3*)vec3Array.LastElement();
  vec3* tailAddress = (vec3*)vec3Array.TailAddress();
  int i = 0;
  for (vec3* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++)
  {
  *ptr = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
  i++;
  }
  i = 0;
  for (vec3* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++, i++)
  {
  var item = *ptr;
  var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
  if (item.x != old.x || item.y != old.y || item.z != old.z)
  { throw new Exception(); }
  }
 }

2015-08-25

用StructLayout和MarshalAs支持复杂的struct

在OpenGL中我需要用UnmanagedArray<mat4>,其中mat4定义如下:

1 /// <summary>
 2 /// Represents a 4x4 matrix.
 3 /// </summary>
 4 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4 * 4)]
 5 public struct mat4
 6 {
 7 /// <summary>
 8 /// Gets or sets the <see cref="vec4"/> column at the specified index.
 9 /// </summary>
10 /// <value>
11 /// The <see cref="vec4"/> column.
12 /// </value>
13 /// <param name="column">The column index.</param>
14 /// <returns>The column at index <paramref name="column"/>.</returns>
15 public vec4 this[int column]
16 {
17 get { return cols[column]; }
18 set { cols[column] = value; }
19 }
20 
21 /// <summary>
22 /// Gets or sets the element at <paramref name="column"/> and <paramref name="row"/>.
23 /// </summary>
24 /// <value>
25 /// The element at <paramref name="column"/> and <paramref name="row"/>.
26 /// </value>
27 /// <param name="column">The column index.</param>
28 /// <param name="row">The row index.</param>
29 /// <returns>
30 /// The element at <paramref name="column"/> and <paramref name="row"/>.
31 /// </returns>
32 public float this[int column, int row]
33 {
34 get { return cols[column][row]; }
35 set { cols[column][row] = value; }
36 }
37 
38 /// <summary>
39 /// The columms of the matrix.
40 /// </summary>
41 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
42 private vec4[] cols;
43 }
44 
45 /// <summary>
46 /// Represents a four dimensional vector.
47 /// </summary>
48 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4)]
49 public struct vec4
50 {
51 public float x;
52 public float y;
53 public float z;
54 public float w;
55 
56 public float this[int index]
57 {
58 get
59 {
60  if (index == 0) return x;
61  else if (index == 1) return y;
62  else if (index == 2) return z;
63  else if (index == 3) return w;
64  else throw new Exception("Out of range.");
65 }
66 set
67 {
68  if (index == 0) x = value;
69  else if (index == 1) y = value;
70  else if (index == 2) z = value;
71  else if (index == 3) w = value;
72  else throw new Exception("Out of range.");
73 }
74 }
75 }

mat4

注意:UnmanagedArray<T>支持的struct,T的大小必须是确定的。所以在mat4里我们用 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4 * 4)] 指定mat4的大小为4个 vec4 * 4个 float * 4个字节(每个float) = 64字节,并且在 private vec4[] cols; 上用 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 规定了cols的元素数必须是4。之后在 vec4 上的 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4)] 不写也可以,因为vec4只有4个简单的float字段,不含复杂类型。

下面是测试用例。

mat4 matrix = glm.scale(mat4.identity(), new vec3(2, 3, 4));

 var size = Marshal.SizeOf(typeof(mat4));
 size = Marshal.SizeOf(matrix);

 UnmanagedArray<mat4> array = new UnmanagedArray<mat4>(1);
 array[0] = matrix;

 mat4 newMatirx = array[0]; // newMatrix should be equal to matrix

 array.Dispose();

如果matrix和newMatrix相等,就说明上述Attribute配置正确了。

总结

到此这篇关于C#+无unsafe的非托管大数组(large unmanaged array in c# without ''unsafe'' keyword)的文章就介绍到这了,更多相关C#+无unsafe的非托管大数组内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • 浅谈C#数组(一)
  • C# 数组删除元素的实现示例
  • c# 如何实现获取二维数组的列数
  • C#如何快速释放内存的大数组详解
  • c# AES字节数组加密解密流程及代码实现
  • 详解c# 数组(Array)
  • C# 删除数组内的某个值、一组值方法详解
  • C# 数组中的 indexOf 方法及使用
  • C#实现的二维数组排序算法示例
  • 浅谈C#数组(二)

go语言源码阅读unsafe包和unsafe.Pointer以及go指针运算

go语言源码阅读unsafe包和unsafe.Pointer以及go指针运算

一、认识指针与指针类型

一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在 32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。当一个指针被定义后没有分配到任何变量时,它的默认值为 nil。

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用在变量名前面添加&操作符(前缀)来获取变量的内存地址(取地址操作),格式如下:

ptr := &v    // v 的类型为 T

其中 v 代表被取地址的变量,变量 v 的地址使用变量 ptr 进行接收,v的类型为 T,ptr 的类型为T,称做 T 的指针类型,代表指针。

func TestPtr(t *testing.T) {
    s := "hello ptr"
    fmt.Printf("s的地址为%p ,地址的10进制表示为%d 值为%s \n", &s, &s, s)
    fmt.Printf("地址的2进制表示为%b", &s)
}

输出:

s的地址为0xc0000484e0 ,地址的10进制表示为824634016992 值为hello ptr
地址的2进制表示为1100000000000000000001001000010011100000

问题1:s地址占用了几个字节?

如果我们数一下大约有 40位二进制,那么是 5个字节?
正确答案是8个字节,我们可以转为unsafe.Pointer然后使用size方法打印出来

func TestPtr(t *testing.T) {
    s := "hello ptr"
    fmt.Printf("s的地址为%p ,地址的10进制表示为%d 值为%s \n", &s, &s, s)
    fmt.Printf("s地址的2进制表示为%b \n", &s)

    var p unsafe.Pointer
    p = unsafe.Pointer(&s)
    fmt.Printf("p地址的2进制表示为%b \n", p)
    size := unsafe.Sizeof(p)
    fmt.Printf("p地址的大小为几个字节 %d \n", size)
}

输出为:

s的地址为0xc00008e4d0 ,地址的10进制表示为824634303696 值为hello ptr 
s地址的2进制表示为1100000000000000000010001110010011010000 
p地址的2进制表示为1100000000000000000010001110010011010000 
p地址的大小为几个字节 8 

二、unsafe源码介绍

unsafe包常用方法

type ArbitraryType int
type Pointer *ArbitraryType
func Alignof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Sizeof(x ArbitraryType) uintptr
  1. Alignof返回变量对齐字节数量
  2. Offsetof返回变量指定属性的偏移量,所以如果变量是一个struct类型,不能直接将这个struct类型的变量当作参数,只能将这个struct类型变量的属性当作参数。
  3. Sizeof 返回变量在内存中占用的字节数,切记,如果是slice,则不会返回这个slice在内存中的实际占用长度。

关于返回值 uintptr类型 在go源代码里

type uintptr uintptr

uintptr 是一个整数类型,它足够大,可以存储. 只有将Pointer转换成uintptr才能进行指针的相关操作。

uintptr是可以用于指针运算的,但是GC并不把uintptr当做指针,所以uintptr不能持有对象, 可能会被GC回收, 导致出现无法预知的错误. Pointer指向一个对象时, GC是不会回收这个内存的。

2.1 ArbitraryType 任意类型

ArbitraryType 表示任意类型,如同interface{},因为用来存储指针地址的,所以相当于存储任意类型。

type ArbitraryType int

2.2 Pointer 指针类型

unsafe中,ArbitraryType任意类型的的指针类型就是Pointer类型。
可以将其他类型都转换过来,然后通过这三个函数,分别能取长度,偏移量,对齐字节数,就可以在内存地址映射中,来回游走。
我们可以用强制类型转化type(a)语法把任意一个指针类型转成unsafe.Pointer
语法如下:

unsafe.Pointer(a)
func TestPointer(t *testing.T) {
    //把一个int类型强制转成 unsafe.Pointer 任意type指针类型
    var i int = 10
    fmt.Println(unsafe.Pointer(&i)) //0xc0000a61a8

    //把一个string类型强制转成 unsafe.Pointer 任意type指针类型
    var s string = "hello"
    fmt.Println(unsafe.Pointer(&s)) //0xc00008e4f0

    //把一个array类型强制转成 unsafe.Pointer 任意type指针类型
    var a [5]int = [5]int{0, 1, 2, 3, 4}
    fmt.Println(unsafe.Pointer(&a)) //0xc0000b0030

    //把一个map类型强制转成 unsafe.Pointer 任意type指针类型
    var m map[string]int8 = map[string]int8{"a": 1, "b": 10, "c": 20, "d": 30}
    fmt.Println(unsafe.Pointer(&m)) //0xc0000a0028

    //把一个slice类型强制转成 unsafe.Pointer 任意type指针类型
    var sli []int8 = []int8{0, 1, 3, 4, 5, 6}
    fmt.Println(unsafe.Pointer(&sli)) //0xc0000b40a0

    //把一个struct类型强制转成 unsafe.Pointer 任意type指针类型
    type st struct {
        w int8
        h int8
    }
    var st1 = st{
        w: 40,
        h: 50,
    }
    fmt.Println(unsafe.Pointer(&st1)) //0xc0000a61b6
}

2.3 Sizeof 占用的内存大小

2.3.1、int等数字类型占用的内存大小
func TestSizeofInt(t *testing.T) {
    //int8,int16,int32,int64,int类型占用的内存地址
    var i8 int8 = 10
    var i16 int16 = 10
    var i32 int32 = 10
    var i64 int64 = 10
    var i int = 10
    fmt.Println(unsafe.Sizeof(i8), unsafe.Sizeof(i16), unsafe.Sizeof(i32), unsafe.Sizeof(i64), unsafe.Sizeof(i))
    //输出为 1 2 4 8 8

    //uint8,uint16,uint32,uint64,uint类型占用的内存地址
    var u8 uint8 = 10
    var u16 uint16 = 10
    var u32 uint32 = 10
    var u64 uint64 = 10
    var u uint = 10
    fmt.Println(unsafe.Sizeof(u8), unsafe.Sizeof(u16), unsafe.Sizeof(u32), unsafe.Sizeof(u64), unsafe.Sizeof(u))
    //输出为 1 2 4 8 8
}
类型type占用内存大小bit占用内存大小byte字节
int8、uint881
int16、uint16162
int32、uint32324
int64、uint64648
int、uint648

注意:int,uint是根据cpu来的,我这里是64位的cpu,所以这里占用了64bit内存,也有32位,16位的。

2.3.2、string类型占用的内存大小

func TestSizeofString(t *testing.T) {
    //string类型占用的内存地址
    var s string = "a"
    fmt.Println(unsafe.Sizeof(s)) //16

    //string类型编译后的存储类型为StringHeader,我们可以强制转化看一下
    stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
    fmt.Println(unsafe.Sizeof(stringHeader.Data)) //8
    fmt.Println(unsafe.Sizeof(stringHeader.Len))  //8

    byteStr := (*byte)(unsafe.Pointer(stringHeader.Data))
    fmt.Println(byteStr)                 //0x11435f6 存储"a"的地址
    fmt.Println(*byteStr)                //97 十进制97
    fmt.Println(string(*byteStr))        // "a" 字符串a
    fmt.Printf("%b", *byteStr)           //1100001 二进制标识的97
    fmt.Println(unsafe.Sizeof(*byteStr)) //1 "a"存储占用的内存地址为1个字节
}

我们保存一个string类型的变量s,值为”a“
问题:此时使用unsafe.Sizeof(s)函数,得出内存占用为16个字节,为什么不是1?
答案:因为s在编译后的类型为 reflect.StringHeader 如下结构

type StringHeader struct {
    Data uintptr
    Len  int
}

此时我们unsafe.Sizeof(s),其实是unsafe.Sizeof(StringHeader)
因为StringHeader.Data为uintptr类型占用8个字节,存储的字符串值的内存地址
StringHeader.Len为int类型也占用8个字节,所以总共16字节。

2.3.3 slice类型占用内存大小

func TestSizeofSlice(t *testing.T) {
    //slice类型占用内存地址
    var sli []int8 = []int8{0, 1, 2, 3, 4, 5}
    fmt.Println(unsafe.Sizeof(sli)) //24

    sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&sli))
    fmt.Println(unsafe.Sizeof(sliceHeader.Data)) //8 uintptr类型
    fmt.Println(unsafe.Sizeof(sliceHeader.Len))  //8 int类型
    fmt.Println(unsafe.Sizeof(sliceHeader.Cap))  //8 int类型
}

2.3.4、自定义struct占用用内大小

func TestSizeofStruct(t *testing.T) {
    //struct类型占用的内存地址
    type arrT struct {
        v [100]int8
    }
    type ST struct {
        b     byte
        i8    int8
        sli   []int8
        s     string
        arrSt arrT
    }

    st := ST{
        b:     1,
        i8:    127,
        sli:   []int8{0, 1, 2, 3, 4},
        s:     "hello",
        arrSt: arrT{v: [100]int8{5, 6, 7, 8}},
    }
    fmt.Println(unsafe.Sizeof(st))       //152 为结构体各个字段的内存之和
    fmt.Println(unsafe.Sizeof(st.b))     //1 byte类型和uint8 一样占用1个字节
    fmt.Println(unsafe.Sizeof(st.i8))    //1 int8类型占用1个字节
    fmt.Println(unsafe.Sizeof(st.sli))   //24 slice类型占用24个字节
    fmt.Println(unsafe.Sizeof(st.s))     //16 string类型16个字节
    fmt.Println(unsafe.Sizeof(st.arrSt)) //100 [100]int8 数组类型为100*int8 为100个字节
}

一个结构体类型占用的内存为组成的各个字段的占用的内存之和。

2.4 Offsetof 指针的位移

Offsetof返回变量指定属性的偏移量,所以如果变量是一个struct类型,不能直接将这个struct类型的变量当作参数,只能将这个struct类型变量的属性当作参数。

func TestOffsetof(t *testing.T) {
    var abc struct {
        a bool
        b int32
        c []int
    }
    fmt.Println("SIZE")
    fmt.Println(unsafe.Sizeof(abc.a)) //1
    fmt.Println(unsafe.Sizeof(abc.b)) //4
    fmt.Println(unsafe.Sizeof(abc.c)) //24
    fmt.Println(unsafe.Sizeof(abc))   //32
    fmt.Println("OFFSET")
    fmt.Println(unsafe.Offsetof(abc.a)) //0
    fmt.Println(unsafe.Offsetof(abc.b)) //4
    fmt.Println(unsafe.Offsetof(abc.c)) //8
}

三、go的指针运算

go指针运算的语法:

pNew = unsafe.Pointer(uintptr(p) + offset)

p和pNew都是unsafe.Pointer类型
这里的p转成了uintptr然后和offset相加,是因为,以下两个用到的函数计算offset,返回值都是uintptr

func Offsetof(x ArbitraryType) uintptr
func Sizeof(x ArbitraryType) uintptr

最常见的用法是访问结构体中的字段或则数组的元素:

3.1 结构体的指针运算如下:

f := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f))
// 等价于 f := unsafe.Pointer(&s.f)

指针的运算思想是:第一个的地址+偏移量

func TestPointer2(t *testing.T) {
    var abc struct {
        a bool
        b int32
        c []int
    }
    //1 结构体abc的地址为
    fmt.Println(unsafe.Pointer(&abc))
    //2 结构体abc.a 的地址为
    fmt.Println(unsafe.Pointer(&abc.a))
    //3 指针运算得出 abc.a的地址为
    fmt.Println(unsafe.Pointer(uintptr(unsafe.Pointer(&abc)) + unsafe.Offsetof(abc.a)))
}

输出为:

=== RUN   TestPointer2
0xc00008e060
0xc00008e060
0xc00008e060
0xc00008e064
0xc00008e064
--- PASS: TestPointer2 (0.00s)
  1. 我们可以得出结构体的地址为,第一个元素的地址
  2. 结构体的指针运算 没问题

3.2 数组的指针运算如下:

e := unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) + i*unsafe.Sizeof(x[0]))
// 等价于 e := unsafe.Pointer(&x[i])

指针的运算思想是:第一个的地址+偏移量
这里偏移量为 i*unsafe.Sizeof(x[0])) i为数组元素的索引index,sizeOf为数组元素的单个大小

func TestPointer3(t *testing.T) {
    var i [4]uint32 = [4]uint32{}
    //1 数组i的地址为
    fmt.Println(unsafe.Pointer(&i))
    //2 数组i[0],第一个元素的地址为
    fmt.Println(unsafe.Pointer(&i[0]))
    //3 数组i[1]的地址为
    fmt.Println(unsafe.Pointer(&i[1]))
    //4 通过指针运算 数组i[1] 的地址为
    fmt.Println(unsafe.Pointer(uintptr(unsafe.Pointer(&i)) + 1*unsafe.Sizeof(i[0])))
    //5 通过指针运算 最后一个 数组i[3] 的地址为
    fmt.Println(unsafe.Pointer(uintptr(unsafe.Pointer(&i)) + 3*unsafe.Sizeof(i[0])))
}

3.3 取出内存外的数据会怎么样?

我们以数组为例子:取出index为10,公共才有4,超出了数组的范围

func TestPointer4(t *testing.T) {
    var i [4]uint32 = [4]uint32{}
    //5 通过指针运算 最后一个 数组i[3] 的地址为
    fmt.Println(unsafe.Pointer(uintptr(unsafe.Pointer(&i)) + 3*unsafe.Sizeof(i[0])))
    //6 超出的数组元素的范围会发生什么?--得到一个数组外其他内容的地址
    fmt.Println(unsafe.Pointer(uintptr(unsafe.Pointer(&i)) + 10*unsafe.Sizeof(i[0])))
}

输出:

=== RUN   TestPointer4
0xc00011e1cc
0xc00011e1e8
--- PASS: TestPointer4 (0.00s)

当我们试图打印超出的地址的内容时候,会报错!需要注意

谢谢您的观看,欢迎关注我的公众号。

image.png

ios – UnsafePointer不再适用于swift 3

ios – UnsafePointer不再适用于swift 3

在我从 swift 2转换为 swift 3之后,会弹出一个错误以显示下面的行

let value = UnsafePointer<UInt32>(array1).pointee

‘init’ is unavailable: use ‘withMemoryRebound(to:capacity:_)’ to temporarily view memory as another layout-compatible type.

在swift2中它就像

let value = UnsafePointer<UInt32>(array1).memory

有人可以解释一下吗?
对不起,我对swift3很新

我做了更改后

let abc = UnsafePointer<UInt32>(array1).withMemoryRebound(to: <#T##T.Type#>,capacity: <#T##Int#>,<#T##body: (UnsafeMutablePointer<T>) throws -> Result##(UnsafeMutablePointer<T>) throws -> Result#>)

但仍然应该对变量有什么价值?对不起,我有搜索但很糟糕,我找不到解决方案

解决方法

你可以试试这个:

let rawPointer = UnsafeRawPointer(array1)
let pointer = rawPointer.assumingMemoryBound(to: UInt32.self)
let value = pointer.pointee

原始指针是用于访问非类型数据的指针.

assumeMemoryBound(to :)可以从UnsafeRawPointer转换为UnsafePointer< T>.

参考:Swift 3.0 Unsafe World

ios – 在swift中不能在不同大小的类型之间使用unsafeBitCast

ios – 在swift中不能在不同大小的类型之间使用unsafeBitCast

当我试图在数组中找到重复项时,我得到错误“不能在不同大小的类型之间进行unsafeBitCast”.我找到了重复的方法.

func uniq<S : SequenceType,T : Hashable where S.Generator.Element == T>(source: S) -> [T] {
    var buffer = [T]()
    var added = Set<T>()
    for elem in source {
        if !added.contains(elem) {
            buffer.append(elem)
            added.insert(elem)
        }
    }
    return buffer
}

func filter() {
    var arrayForSearch = mp3Files as! [String]
    var filteredArray = uniq(arrayForSearch)
    println("filtered array \(filteredArray)")
}

我在这个链接enter link description here上找到的重复查找方法.我使用Xcode 6和Swift 1.2

这段代码中有数组.

var mp3Files: Array<String!>!
func exportData() {
    var generalURL: [AnyObject]?
    var arrayFiles: Array<NSURL!>!
    var directory = fileManager.URLsForDirectory(NSSearchPathDirectory.DocumentDirectory,inDomains: NSSearchPathDomainMask.UserDomainMask)
    var urlFromDirectory = directory.first as! NSURL

    var file = fileManager.contentsOfDirectoryAtURL(urlFromDirectory,includingPropertiesForKeys: nil,options: NSDirectoryEnumerationoptions.SkipsHiddenFiles,error: nil)!
    println("file \(file)")

    mp3Files = file.map(){ $0.lastPathComponent }.filter(){ $0.pathExtension == "mp3" }

  println("mp3 files  \(mp3Files)")
}

当我在游乐场中编写此代码时,它可以工作.
一个例子

var array = ["Apple","Mac","iPhone","iPad Air","Apple","Air","Air"]
var filteredArray = Array(Set(array))

println(filteredArray)

我如何在我的项目中使用它?

解决方法

var mp3Files: Array<String!>!

哇,这是很多感叹号……他们不需要.

var arrayForSearch = mp3Files as! [String]

并且mp3Files的类型永远不会与[String]相同,所以你不能强制它们之间的强制转换(如果它允许你会崩溃).

你经常使用隐式解包的选项.只在某些特殊情况下才需要它们.只需将mp3Files更改为[String](在这种情况下,你根本就不需要as !,你不应该经常使用as!).

同样,arrayFiles(你从不使用)应该只是[NSURL],而不是Array< NSURL!> !.

关于Swift 5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes...的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于C#+无unsafe的非托管大数组示例详解(large unmanaged array in c# without ‘unsafe’ keyword)、go语言源码阅读unsafe包和unsafe.Pointer以及go指针运算、ios – UnsafePointer不再适用于swift 3、ios – 在swift中不能在不同大小的类型之间使用unsafeBitCast的相关信息,请在本站寻找。

本文标签: