I have accidentally discovered something - something good I believe.
A way of importing C-arrays
into Swift
, which makes it possible to access the elements of an array by indexing, eliminating the need to deal with potentially large tuples
.
I was trying to import the following C-array
into Swift
, but I immediately ran into a stumbling block.
struct Packet {
unsigned long size;
char bytes [1]; // this style of trailing array is no longer valid
};
Only the first byte of the array is visible in Swift
, because Swift
seems to always expect something like one of these:
struct FriendlyPacket {
unsigned long size;
char * bytes ;
};
struct FixedSizePacket {
char bytes [8192];
};
Following @scanon's advice below, I used a flexible array instead:
struct Packet {
unsigned long size;
char bytes []; // using a flexible array instead
};
This time, however, I was promptly greeted with a new problem: Swift
can't see the bytes
field at all!
Luckily, there is a simple solution: use a thin adaptation
layer.
adaptor: Packet -> FriendlyPacket
// In C
// Case 1 - flexible array
Packet p = ...
FriendlyPacket fp = {p.size, p.bytes};
// Case 2 - fixed-size array
FixedSizePacket p2 = ...
FriendlyPacket fp2 = {sizeof (p2.bytes), p2.bytes};
// Back in Swift
Access elements of bytes in a FriendlyPacket simply by indexing, without having to deal with tuples!
Details Here
// Packet.h
#ifndef Packet_h
#define Packet_h
struct Packet {
unsigned long size;
char bytes [ ];
};
typedef struct Packet Packet;
Packet * Packet_allocate (unsigned long size);
void Packet_print (Packet *);
struct FriendlyPacket {
unsigned long size;
char * bytes;
};
typedef struct FriendlyPacket FriendlyPacket;
FriendlyPacket Packet_adapt (Packet *);
#endif /* Packet_h */
// Packet.c
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "Packet.h"
//
// --------------------------------------------------------
//
Packet * Packet_allocate (unsigned long size) {
Packet * ptr = malloc (sizeof (Packet) + size * sizeof (char));
assert (ptr);
ptr->size = size;
ptr->bytes [0] = 5;
ptr->bytes [size - 1] = 7;
return ptr;
}
void Packet_print (Packet * ptr) {
printf ("Packet: size: %lu\n", ptr->size);
for (int x = 0; x < ptr->size; ++x) {
printf ("\tbytes [%d]: %d\n", x, ((int) (ptr->bytes [x])));
}
}
FriendlyPacket Packet_adapt (Packet * ptr) {
FriendlyPacket u = {ptr->size, ptr->bytes};
return u;
}
// Test.swift
@main
struct T1 {
static func main () async {
let u : UnsafeMutablePointer <Packet> = Packet_allocate (UInt (5))
Packet_print (u);
// Can't modify u, because only the first byte is visible in Swift. (or not visible at all in the case the flexible array.)
// Adapt it to a form Swift can recognize
let fp = Packet_adapt (u);
print ("FriendlyPacket: size: \(fp.size)")
for i in 0..<fp.size {
print ("\tbytes [\(i)]:\(fp.bytes [Int (i)])")
}
// Now can modify it
for i in 0..<fp.size {
fp.bytes [Int (i)] *= 3
}
Packet_print (u);
}
}
I submit this for your perusal.
Thank you.
Edit: use flexible array.