Pointers, Pointer Arithmetic, and Raw Data in Swift
If you just want to do it directly, UnsafePointer<T>
can be manipulated arithmetically:
let oldPointer = UnsafePointer<()>
let newPointer = oldPointer + 10
You can also cast a pointer like so (UnsafePointer<()>
is equivalent to void *
)
let castPointer = UnsafePointer<MyStruct>(oldPointer)
How to do pointer arithmetic on UnsafeMutablePointer and get String in Swift 3
You have to bind the raw pointer to an UInt8
pointer:
let bytes = (data + 1).bindMemory(to: UInt8.self, capacity: length - 1)
Now you can create a buffer pointer referring to that byte range
let buffer = UnsafeBufferPointer(start: bytes, count: length - 1)
which (as a Sequence
) can be passed to
let str = String(bytes: buffer, encoding: .ascii)
Pointers in swift: purpose of UnsafeMutableBufferPointer
UnsafeMutablePointer<T>
is designed for accessing a single element of type T
. Its interface is designed for accessing a single scalar value.
UnsafeMutableBufferPointer<T>
, on the other hand, is designed to access a group of elements of type T
stored in a contiguous block of memory. Its interface is designed to access individual elements of the range, and also for treating the entire collection as a single unit (e.g. the generate
method).
If you access bytes inside NSData
, UnsafePointer
alone is not sufficient, because you need to know the length of data. In contrast, a single UnsafeBufferPointer
is sufficient to represent the data, because it provides both the initial location and the number of elements.
Pointer and malloc in Swift
You can use malloc
from Swift, it returns a "raw pointer":
var p: [UnsafeMutableRawPointer?] = Array(repeating: nil, count: 10000)
var allocatedMB = 0
p[allocatedMB] = malloc(1048576)
memset(p[allocatedMB], 0, 1048576)
Alternatively, use UnsafeMutablePointer
and itsallocate
and initialize
methods:
var p: [UnsafeMutablePointer<UInt8>?] = Array(repeating: nil, count: 10000)
var allocatedMB = 0
p[allocatedMB] = UnsafeMutablePointer.allocate(capacity: 1048576)
p[allocatedMB]?.initialize(to: 0, count: 1048576)
Swift, OpenGL and glVertexAttribPointer
To replicate the offsetof
functionality you just need to know at which byte offset does each field lie in your structure.
In your case, assuming your struct is tightly packed, the first call should receive 0
, and the second 4 * GLfloat
because that's the size of the first component. I'm not sure how to extract this data directly from the structure, especially since you're using tuples.
To illustrate, your structure:
struct Vertex {
var position: (x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat)
var color: (r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat)
}
is most probably laid out like that:
GLfloat // <-- structure start // <-- position
GLfloat
GLfloat
GLfloat
GLfloat // <-- color
GLfloat
GLfloat
GLfloat
Hence the position
lies at offset 0
, and color
at 4 * GLfloat
.
To create a pointer with a value 16, this answer looks relevant:
let ptr = UnsafePointer<()> + 16
So I suppose this should work as well:
let ptr = UnsafePointer<()> + sizeof(GLfloat) * 4
How to get bytes out of an UnsafeMutableRawPointer?
load<T>
reads raw bytes from memory and constructs a value of type T
:
let ptr = ... // Unsafe[Mutable]RawPointer
let i16 = ptr.load(as: UInt16.self)
optionally at a byte offset:
let i16 = ptr.load(fromByteOffset: 4, as: UInt16.self)
There is also assumingMemoryBound()
which converts from a Unsafe[Mutable]RawPointer
to a Unsafe[Mutable]Pointer<T>
, assuming that the pointed-to memory contains a value of type T:
let i16 = ptr.assumingMemoryBound(to: UInt16.self).pointee
For an array of values you can create a "buffer pointer":
let i16bufptr = UnsafeBufferPointer(start: ptr.assumingMemoryBound(to: UInt16.self), count: count)
A buffer pointer might already be sufficient for your purpose, it
is subscriptable and can be enumerated similarly to an array.
If necessary, create an array from the buffer pointer:
let i16array = Array(i16bufptr)
As @Hamish said, more information and details can be found at
- SE-0107 UnsafeRawPointer API
Passing swift struct pointer to C function
There are two problems: You cannot take the address of a constant (defined with let
),
and you can pass the address of a variable only to function parameters.
Assuming that your C function is
void myFunc(const void *data);
then this would work:
var a = Foo()
myFunc(&a)
However, instead of making assumptions about identical alignment in C and Swift, you
should perhaps better define the structure in your C API:
struct Foo {
float a;
float b;
float c;
double d;
};
void myFunc(const struct Foo *data);
and use that from the Swift code:
var a = Foo(a: 0, b: 0, c: 0, d: 0)
myFunc(&a)
Convert UnsafeMutableRawPointer to UInt64
(U)Int
has the size of a pointer on all platforms (32 bit or 64 bit), so you can always convert between Unsafe(Mutable)(Raw)Pointer
and Int
or UInt
:
let pointer: UnsafeRawPointer? = ...
let intRepresentation = UInt(bitPattern: pointer)
let ptrRepresentation = UnsafeRawPointer(bitPattern: intRepresentation)
assert(ptrRepresentation == pointer)
Your code
let intRepresentation = UInt64(bitPattern: pointer)
does not compile because UInt64
does not have an initializer taking a pointer argument, and that is because pointers can be 32 bit or 64 bit. (And even on a 64-bit platform, UInt
and UInt64
are distinct types.)
If you need an UInt64
then
let intRepresentation = UInt64(bitPattern:Int64(Int(bitPattern: pointer)))
does the trick.
Related Topics
Swift, Auto Resize Custom Table View Cells
Why Should Not Directly Extend Uiview or Uiviewcontroller
Swift - Avaudioplayer, Sound Doesn't Play Correctly
Arkit - Viewport Size VS Real Screen Resolution
Division Not Working Properly in Swift
Why How to Use Codable with a Project Language Version of Swift 3.3
Can the Conversion of a String to Data with Utf-8 Encoding Ever Fail
Implementing a Function with a Default Parameter Defined in a Protocol
Does a Mutating Struct Function in Swift Create a New Copy of Self
Firestore Order by Time But Sort by Id
Initialize Lazy Instance Variable with Value That Depends on Other Instance Variables
Creating a Countableclosedrange<Character>
How to Use Uiwindowscene.Windows on iOS 15
Working with C Strings in Swift, Or: How to Convert Unsafepointer<Cchar> to Cstring