Convert unsinged char array from objective-c to UnsafeMutablePointer<UInt8> swift - objective-c

I have an unsigned char array in .h file. and, also I have a function that takes unsigned char array as input. When I try to call this function in swift, it gets UnsafeMutablePointer<UInt8>. So, automatic objective-c to swift converter thinks unsigned char should be converted as UnsafeMutablePointer<UInt8>. But, I can not pass my variable to this function directly. Because I get,
Cannot convert value of type '(UInt8, UInt8, UInt8, UInt8, UInt8)' to expected argument type 'UnsafeMutablePointer<UInt8>!'
Length of this array is static. So, I can create
let key = UnsafeMutablePointer<UInt8>.allocate(capacity: 64);
and, also I can get value by KEY.0, KEY.1 ... etc. So, all I need is to create a for loop to read value from KEY and assign it to key
for index in 1...64 {
key[index] = KEY[index];
}
but, this gives compilation error as:
Value of tuple type '(UInt8, UInt8, UInt8, UInt8, UInt8)' has no member 'index'
so, first question, how I can get any value from KEY by index. Second is, is there any easier way to convert a unsigned char array to UnsafeMutablePointer<UInt8>

A C array
unsigned char ckey[64];
is imported as a tuple in Swift:
public var ckey: (UInt8, ..., UInt8)
and one cannot access the tuple elements by subscripting with an index.
(Well, you can when using Mirror).
However:
The address of a C array is the same as the address of the first
array element, and
for structures imported from C, Swift preserves the memory layout.
The latter was confirmed by Apple engineer Joe Groff:
... You can leave the struct defined in C and import it into Swift. Swift will respect C's layout.
Therefore you can pass the address of the first tuple element to
the function:
f(key: &ckey.0)
Of course – as in C – the information about the size of the array is
lost, so the array should be NUL-terminated, or f should know
about the array size. Alternatively, pass the size
as an additional argument to the function:
foo(key: &ckey.0, length: MemoryLayout.size(ofValue: ckey))

Related

Converting an Objective C array declaration to Swift

How would I translate this Obj-C into Swift? I'm not sure about the new Swift 2 syntax and all.
unsigned char pixel[4] = {0};
According to the comments there seems to be an additional question about what the Objective-C code means: unsigned char pixel[4] declares pixel as an array of 4 unsigned char's. The = {0} initializes all elements of the array to 0.
Hence the simplest conceptual equivalent in Swift is:
var pixel: [UInt8] = [0,0,0,0]
Unlike C and Objective-C, Swift does not allow specifying the size of the array in advance and thus all four zeroes must be given to obtain the correct length - in C and Objective-C the extra zeroes can be omitted for brevity since it is already known that the array's size is 4.
Arguably you could use CUnsignedChar instead of UInt8 (as the unsigned char in C is not strictly guaranteed to be UInt8), but it is unnecessary unless you're going to be passing the values to a C function expecting unsigned char. In any case they are extremely likely to be the same type, and on the odd platforms where they aren't the same type it is more likely that the C code is actually wrong and used unsigned char where they meant uint8_t.
You can do it this way :
var pixel = [UInt8](count:4, repeatedValue:0)
Or :
var pixel:[UInt8] = [0,0,0,0]
Swift equivalent of unsigned char is CUnsignedChar
var pixel : [CUnsignedChar]()
You cannot give fixed length arrays in CMutablePointers in swift. So you have to declare like this. Reference
See this link to overcome this issue

0 randomly becomes 55?

I have an app in which I pass an dictionary of type [string:[int]] from a swift file to an objective c file, then as NSDictionary. Through that process, the data formats get all screwed up, but in the end I am able to access each array of ints from a string, as would be expected from an NSDictionary. Unfortunately, somewhere along the line the integers get converted to type 'id', and to change that back to int, I did this:
NSLog(#"%d",(int)theThreeNotes[#"0"][0])
theThreeNotes[#"0"][0] should be 0, but it is logged as 55. How do you fix this?
If the dictionary is passed to Objective-C, all the integers will become NSNumber instances. NSDictionary/NSArray cannot hold primitive values. That means you will have to call integerValue on the number, not cast it blindly to int.
Or just print it using:
NSLog(#"%#", theThreeNotes[#"0"][0])

What is int foo[] = {1200,100} and how do I recreate it in Swift?

Testing out some third party objective-C code I see the following:
int beepData[] = {1200,100};
What am I looking at here? An int is being created from a pair of other integers? I've not seen this feature before.
I would also like to know how to create the same variable in Swift.
EDIT
I assumed this was returning an int, not an array. The code I'm reviewing looks like this:
int beepData[] = {1200,100};
[[DTDevices sharedDevice] barcodeSetScanBeep:TRUE volume:10 beepData:beepData length:sizeof(beepData) error:nil];
Where the method signature I am intending to pass the variable to is:
-(BOOL)barcodeSetScanBeep:(BOOL)enabled volume:(int)volume beepData:(int *)data length:(int)length error:(NSError **)error;
I guess the right question might have been - what is (int *) and how might I create one in Swift?
What am I looking at here?
That is an array of ints, with two elements.
[How can I] create the same variable in Swift?
The same variable in swift might be declared as:
var beepData : [Int] = [ 1200, 100 ]
You might find this answer about different ways to declare an array in C useful
What is (int *)
It's an int pointer, it points to the memory address of an int. Incrementing it would move along the memory addresses (in int-sized chunks) and point to the next bit of memory.
[1][3][5][4][2]
^
This little arrow represents an int*. Even though it currently points to 1,
incrementing it doesn't equal 2. In this case it would equal 3, the value of the int in the next block of memory.
[1][3][5][4][2]
^
How might I create one in Swift?
To be quite honest, I'm not sure if Swift has pointers in the normal sense. I've not used it a great deal. However, if you are porting that method, I'd probably give it an array of ints.
func barcodeSetScanBeep(enabled : Bool, volume : Int, beepData: [Int], length : Int, error : NSError)
That's a C array, declared with 1200 and 100 as the members of the array.
Its declared with the type, and a bracket with the size (or empty for compiler deduced size), such as int cArrayOfInts[] = blahblahblah.
Note how the members of the array can be primitives, instead of objects. This isn't possible in Objective-C.
To recreate this in swift, simply use var beepData = [1200, 100] and it will be type inferred to an array of Ints.
James already answered the particulars of your question - consider this some additional information.
Declarations in C are based on the types of expressions, not objects. If you have an array of integers and you want to access the i'th integer, you would write
x = arr[i];
The type of the expression arr[i] is int, so the declaration of arr is written as
int arr[N]; // arr is an N-element array of int
Similar logic applies to pointer declarations; if you have a pointer to a double and you want to access the pointed-to value, you'd write
y = *p;
The type of the expression *p is double, so the declaration of p is written as
double *p;
Same for function declarations; you call a function that returns an integer as
x = f();
The type of the expression f() is int, so the declaration of the function is written as
int f( void ); // void means the function takes no parameters
C declaration syntax uses something called a declarator to specify an object's array-ness, pointer-ness, or function-ness. For example:
int x, arr[10], *p, f(void);
declares x as a plain int, arr as a 10-element array of int, p as a pointer to an int, and f as function taking no parameters and returning int.
You'll occasionally see pointer declarations written as T* p, however they will be parsed as T (*p); the * is always part of the declarator, not the type specifier.
C declaration syntax allows you to create some pretty complex types in a compact format, such as
int *(*(*f[N])(void))[M];
In this declaration, f is an N-element array of pointers to functions returning pointers to M-element arrays of pointers to int.
In your declaration
int beepData[] = {1200, 100};
beepData is being declared as an array of an unknown size; the size is taken from the number of elements in the initializer {1200, 100}, in this case 2.
I know nothing about Swift, so I wouldn't know how to translate the C code to it. The best I can do is explain how the C code works.

2 dimensional C array as Objective C parameter, malloc incompatible with sizeof operand

I need to create a pointer to a 2 dimensional C array which will be passed as a parameter to a function later. This is what I am attempting:
int64_t (*results)[numSamples] = malloc(sizeof(int64_t[numSamples])*amountPossible);
The result I was hoping for is a pointer to a 2 dimensional array that would effectively be something like int64_t[amountPossible][numSamples], but using Analyze in Xcode I get the warning
Result of 'malloc' is converted to a pointer of type
'int64_t[numSamples]', which is incompatible with sizeof operand type
'int64_t[numSamples]'
numSamples will always be the same value, but amountPossible is variable. Is there a better way to do this?
This appears to be a bug in the analyzer. The only permutation I discovered which doesn't trip the analyzer is to break up the statement:
size_t bytes = sizeof(int64_t[numSamples]) * amountPossible;
int64_t (*results)[numSamples] = malloc(bytes);
Which shouldn't of course be required!
Report it as a bug to Apple.

Objective-C pointer values

I'm compiling an application using X-Code 3.2.6 (64-bit). The application is compiling against the 10.5 SDK and in 32 Bit Intel Architecture.
I've declared a character array as:
char iptmp[ARRAY_SIZE];
so I'm calling a function thus:
myfunc(&iptmp);
Where myfunc is declared:
void myfunc(char** value)
{
...
};
With the intention of loading the character array with the contents of another string with strncpy. When you see what's below you might appreciate why I don't simply do something like: strcpy(iptmp, myfunc()); but here is the problem:
Value of iptmp prior to function call: 0xb0206f5a
Value of *value in function: 0xffffb020
I've tried various things to resolve this problem, but the only thing that seems to stick is to receive a UINT32 value and cast:
myfunc((UINT32) &iptmp);
void myfunc(UINT32 value)
{
char* target = (char*) value;
...
}
This is causing havoc in my code. What is going on with the pointer value?
What happens here is that iptmp is a location in memory. If you write iptmp you will get the address of the aray. However, you will also get the address of it if you write &iptmp. However, you assume that you will get a pointer to a pointer to the array.
The best way to handle this is simply doing:
void myfunc(char * value)
{
...
};
The pointer value will point to the array, which you can modify anyway you like.
When you derefence *value, you're saying "take the pointer stored in value, and load the bytes at that location as if they were a char *". But the bytes at the location pointed to by value aren't a char * - they're the first bytes of iptmp[] itself (in your case, the first 4 bytes).
The root cause is that you're passing &iptmp, which has type char (*)[ARRAY_SIZE], to a function that expects a char ** parameter. These types are not interchangeable, as you've found. The correct declaration for the function would be:
void myfunc(char (*value)[ARRAY_SIZE])
{
/* ... */
}
You can then pass &iptmp, and you will find that *value has the value that you expect.
Why not just
void myfunc(char *value)
{
strncpy(value, ...);
}
and
myfunc(iptmp);
Remember, arrays and pointers in C are not the same things, although you may have heard the opposite many times. An array is an object whose size is equal to its length multiplied by the size of each of its elements, while a pointer is just like a single int but with special semantics.
Hence, the two expressions iptmp and &iptmp yield the same result, namely the starting address of the array. iptmp yields a pointer value for convenience, but that doesn't mean that the object iptmp is a pointer itself.
By attempting to get the address of the address of the array, you really intend to perform &(&iptmp), which is a meaningless, erroneous operation.