How to reinterpret_cast in Swift?
withMemoryRebound(to:capacity:_:)
can be used
... when you have a pointer to memory bound to one type and you need to access that memory as instances of another type.
Example: Take the address of the general struct, then rebind and dereference the pointer:
let general = GeneralStruct()
let specific = withUnsafePointer(to: general) {
$0.withMemoryRebound(to: SpecificStruct.self, capacity: 1) {
$0.pointee
}
}
If both types have the same size and a compatible memory layout then you can also use unsafeBitCast(_:to:)
:
Use this function only to convert the instance passed as x to a layout-compatible type when conversion through other means is not possible.
Warning: Calling this function breaks the guarantees of the Swift type system; use with extreme care.
Example:
let specific = unsafeBitCast(general, to: SpecificStruct.self)
How to reinterpret_cast with pointer to MTLBuffer Swift adaptation
Obviously I can't verify this on my machine, but you should be able to do something like this.
var noiseRaw = noiseBuffer.contents()
let samples = noiseRaw.bindMemory(
to: RandomSample.self,
capacity: NOISE_BLOCK_SIZE * NOISE_BLOCK_SIZE
)
for i in 0..<NOISE_BLOCK_SIZE * NOISE_BLOCK_SIZE {
let sample = samples + i
sample.pointee.componentSample = Float.random(in: 0..<1)
sample.pointee.emitterSample = Float.random(in: 0..<1)
sample.pointee.rrSample = Float.random(in: 0..<1)
}
How to do a reinterpret_cast with Obj-C?
After the clarification you are after reinterpret_cast
:
You are correct you can do it with a union
. If you want to do it inline you can use a cast, address-of and indirection...
The C-style cast (type)expr
in both (Objective-)C and C++ works similarly: if the equivalent of a static_cast
is appropriate it does that, e.g. between int
and float
and other value types; otherwise it will do the equivalent of a reinterpret_cast
, e.g. between pointer-types.
So you just need to convert to a pointer, cast, and indirect. E.g.:
int z = 0xDEADBEEF;
float y = *(float *)&z;
NSLog(@"%d -> %f", z, y);
Yes it's a bit ugly, but then what you are doing is as well ;-) To make it a bit nicer define it as a macro:
#define REINTERPRET(type, expr) (*(type *)&(expr))
which you can use as:
int z = 0xDEADBEEF;
float y = REINTERPRET(float, z);
NSLog(@"%d -> %f", z, y);
As with reinterpret_cast
, you should use this sparingly and with care!
HTH
With or without reinterpret_cast
A C style cast is nothing but the C++ cast that succeeds from the predefined order of:
- const_cast
- static_cast
- static_cast, then const_cast
- reinterpret_cast
- reinterpret_cast, then const_cast
In this case they are doing the same thing. However, if you are using C++ it is better to use C++ style of explicit casting because they are more indicative of the intent and also it's always better to be explicit about what casting you need than be at the mercy of the compiler to chose one for you.
Swift type casting and parenthesis
It looks like you can add an arbitrary number of parentheses (e.g. (((Int64)))
). The main reason for the parentheses is to make a cast like (object as SomeClass).method()
reinterpret_cast vs strict aliasing
I know that
char*
is allowed to point to anything, but I also have aT*
that points to achar*
.
Right, and that is a problem. While the pointer cast itself has defined behaviour, using it to access a non-existent object of type T
is not.
Unlike C, C++ does not allow impromptu creation of objects*. You cannot simply assign to some memory location as type T
and have an object of that type be created, you need an object of that type to be there already. This requires placement new
. Previous standards were ambiguous on it, but currently, per [intro.object]:
1 [...] An object is created by a definition (6.1), by a new-expression (8.3.4), when implicitly changing the active member of a union (12.3), or when a temporary object is created (7.4, 15.2). [...]
Since you are not doing any of these things, no object is created.
Furthermore, C++ does not implicitly consider pointers to different object at the same address as equivalent. Your &data[pos]
computes a pointer to a char
object. Casting it to T*
does not make it point to any T
object residing at that address, and dereferencing that pointer has undefined behaviour. C++17 adds std::launder
, which is a way to let the compiler know that you want to access a different object at that address than what you have a pointer to.
When you modify your code to use placement new
and std::launder
, and ensure you have no misaligned accesses (I presume you left that out for brevity), your code will have defined behaviour.
* There is discussion on allowing this in a future version of C++.
Passing and Casting Object Types in Swift
Why you do that? You can simply implement Hashable protocol and override == operator to compare two objects. Then you can simply write: x == y without any loops.
Is it possible to pass a dynamically allocated array to a function that requires an array reference?
You can use reinterpret_cast
for this. Using an alias for the array type to make the code easier to read, you would have something like:
void my_func(int (&arr)[10])
{
for (auto e : arr)
std::cout << e << " ";
}
int main()
{
using array_t = int[10];
int* my_arr = new int[10]{1,2,3,4,5,6,7,8,9,10};
my_func(reinterpret_cast<array_t&>(*my_arr));
}
And you can see that working at this live example.
Related Topics
Changing Associated Value of Enum Swift
A Warning "'Init()' Is Deprecated". [Swift, iOS App, Learning Model]
Swift - Nsurl Fileurlwithpath Not Unwrapped
Restrictions Around Protocols and Generics in Swift
Combining Scenekit and Spritekit in a Single Screen
Swift Ensembles Set Up & Ubiquitycontaineridentifier
How to Calculate a Distance Between Two Anchorentities
Swiftui - Form with Error Message on Button Press and Navigation
Scanning Ble Peripheral and Connecting to It
Access Safari Bookmarks in Macos Mojave Programmatically
Nsnumber/Nsdecimalnumber Bizarre Behavior
How to Observe Torchlevel in Swift
How to Reinterpret_Cast in Swift
Must Call a Designated Initializer of The Superclass 'Day' Error
Xcode Swift: Could Not Insert New Outlet Connection
Nstimer() - Timer.Invalidate Not Working on a Simple Stopwatch