How can I declare and use a C union type in Swift?
I tried:
var value: union {
var output: CLongLong
var input: [CInt]
}
but it does not work...
UPDATED: I want to use union to split a 8 bytes number
to 2 x 4 bytes number
.
How can I declare and use a C union type in Swift?
I tried:
var value: union {
var output: CLongLong
var input: [CInt]
}
but it does not work...
UPDATED: I want to use union to split a 8 bytes number
to 2 x 4 bytes number
.
As the Apple Swift document , Enumerations can do similar thing and more.
Alternatively,
enumeration
members can specify associated values of any type to be stored along with each different member value, much asunions
orvariants
do in other languages. You can define a common set of related members as part of one enumeration, each of which has a different set of values of appropriate types associated with it.
1) If you just want to split a 8 bytes number to 2 x 4 bytes numbers, as you might have known, the Bitwise Operation of Swift could help. Just like
let bigNum: UInt64 = 0x000000700000008 //
let rightNum = (bigNum & 0xFFFFFFFF) // output 8
let leftNum = (bigNum >> 32) // output 7
2) If you want to simulate the union
behaviour like C
language,
I tried a way like this. Although it works, it looks terrible.
enum Number {
case a(Int)
case b(Double)
var a:Int{
switch(self)
{
case .a(let intval): return intval
case .b(let doubleValue): return Int(doubleValue)
}
}
var b:Double{
switch(self)
{
case .a(let intval): return Double(intval)
case .b(let doubleValue): return doubleValue
}
}
}
let num = Number.b(5.078)
println(num.a) // output 5
println(num.b) // output 5.078
Well, there is no direct support of unions, in Swift, but we can use enumeration for our purpose.
Ex-
enum Algebra {
case Addition(Double, Double)
case Substraction(Double, Double)
case Square(Double)
var result : Double {
switch(self)
{
case .Addition(let a, let b): return a + b
case .Substraction(let a, let b): return a - b
case .Square(let a): return a * a
}
}
}
let solution = Algebra.Addition(5, 3)
println(solution.result) //Output: 8.0
8 bytes number
to 2 x 4 bytes numbers
–
Battled Swift discourages "unsafe" programming patterns like union
, however, there is a workaround. It's a bit ugly, but here goes (using Xcode 7.2)...
struct VariantA {
var oneField: Int // 8 bytes
struct VariantB {
var firstField: UInt32 // first 4 bytes
var secondField: UInt32 // second 4 bytes
}
var variantB: UnsafeMutablePointer<VariantB> {
mutating get {
func addressOf<U>(something:UnsafePointer<U>)
-> UnsafeMutablePointer<VariantB> {
return UnsafeMutablePointer<VariantB>(something)
}
return addressOf(&oneField)
}
}
}
Now a quick check of sizeof(VariantA)
will show the whole structure still takes up only eight bytes (which is one 64-bit integer). If we now create an instance like this var a = VariantA(oneField: 1234567890987654321)
then we can query the components like this a.oneField
which will return the initial value 1,234,567,890,987,654,321 and also a.variantB.memory.firstField
will return 2,976,652,465 and a.variantB.memory.secondField
will return 287,445,236.
We can change one of the components like this a.variantB.memory.firstField++
and then observe that this changes the original value of a.oneField
to 1,234,567,890,987,654,322 as expected.
The ugly parts for me are the occurrences of the words "unsafe", "pointer" and .memory.
as well as that addressOf
helper function which is only there to overcome a compiler error in Xcode 7.2!
Perhaps working with lower-level structures that require byte-level manipulation like this should not be done in a high level language like Swift at all. Have you considered writing this part of your project in a .c file? With a suitable bridging header you can still do the majority of your project in Swift.
Here I define MyUnion
which has two member named f
and g
. As you see, union
is unsafe, and enum
with associated value is preferred, though it's a bit different from union
.
// Simulate union of the C programming language
// f and g share memory
struct MyUnion {
fileprivate var ivar: UInt32 = 0 // Shared memory, private is better.
var f: Float {
get { return Float.init(bitPattern: ivar) }
set { ivar = newValue.bitPattern }
}
init(f: Float) { self.f = f }
var g: Int32 {
get { return Int32(bitPattern: ivar) }
set { ivar = UInt32(bitPattern: newValue) }
}
init(g: Int32) { self.g = g }
}
var u = MyUnion(f: 13.12)
u.f // 13.12
u.g // 1095887749
u.ivar // 1095887749
u.f = -99.123
u.f // -99.123
u.g // -1027195142
u.ivar // 3267772154
u = MyUnion(g: -1)
u.f // nan
u.g // -1
u.ivar // 4294967295
Well, you can make a C union in a struct in ObjC code, and when imported in swift it will behave like it's supposed to. Source: https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_structs_and_unions_in_swift
"Swift imports C unions as Swift structures. Although Swift doesn’t support natively declared unions, a C union imported as a Swift structure still behaves like a C union."
Your union doesn't specify the type of the structure, so I would assume you are always deriving that from the context (you always know if the value is either output
or input
). In that case, I would translate it into two separate structs:
struct OutputValue {
...
}
struct InputValue {
...
}
If you want the structs to have some common properties/methods, declare a protocol
for it.
Couldn't one do something like this:
struct MyUnion { // A poor man's |union| in Swift.
var lsb = UInt8(0)
var msb = UInt8(0)
var uint16 : UInt16 {
get { return (UInt16(msb) << 8) + UInt16(lsb) }
set { self.msb = UInt8(newValue >> 8); self.lsb = UInt8(newValue) }
}
}
© 2022 - 2024 — McMap. All rights reserved.
union
in C, and in all cases unpack whatever data is contained within with bit-wise operators. – Tonisha