Objective-C pointer values - objective-c

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.

Related

No matching function for call to pthread_create Objective-C ARC conversion

converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:
modify it to take a std::string and do any required conversion to NSString * within it; or
write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.
Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.
Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).
(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)
HTH

Reason for getting random garbage value in Xcode

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSLog(#"HELLo %i");
}
return 0;
}
I tried to print a integer value in objective-C XCode compiler but i forgot to specify the variable. When i executed it, i got some garbage value like 4144 for integer, 98489866930523080936567411769317361312251531363217687183360.000000 for float and values like that for other data types too.
I'm just really interested in knowing the reason behind this garbage output ??????
This is because the values to print are passed in registers or on the stack/frame to the function that will print the results.
The printf() function (or in your case NSLog), and functions like it, take 1 or more parameters. The maximum number of parameters is not specified by the function header.
This function first gets a pointer to the string to print, and parses it. Every time it encounters %i, %d, %f etc., it starts pulling the values to print off of the stack, one by one.
In your case, the value it is pulling is uninitialized since it isn't specified, and in this case its value translated to 4144 when interpreted as an integer.
There are some good answers here:
How do vararg functions find out the number of arguments in machine code?

Why cStringUsingEncoding: returns const char * instead of char *?

cStringUsingEncoding: returns a "const char *" despite it is returning a dynamically allocated C string(from it's documentation). So, what is the purpose of const here? We could simply modify the returned C string by casting to char *.
cStringUsingEncoding:
The returned C string is guaranteed to be valid only until either the
receiver is freed, or until the current autorelease pool is emptied,
whichever occurs first.
I think library is following the common practice of pointer-to-const; it's not expected to be modified or released.
From Objective-C runtime;
const char * object_getClassName(id obj) -- Nothing specified about the returned string.
char * method_copyArgumentType(Method method, unsigned int index) -- You must free the string with free(). (May be it's advising because of it's returning a copy.)
The common pattern is that you should not modify buffers that you don't own. const documents and (somewhat) enforces this.
As for cStringUsingEncoding:, The documentation is saying that the returned buffer is only valid as long as the NSString from which you received it, or for the duration of the current autorelease pool. This implies that you do not own the returned buffer, because you're not expected to release it.
Your last two examples from the runtime follow the same convention:
const char * object_getClassName(id obj)
Doesn't inform you that you should release the buffer, and the name doesn't contain any indication that you own the buffer. Therefore you don't free() it, and you don't modify it.
char * method_copyArgumentType(Method method, unsigned int index)
The docs explicitly tell you that you should free the buffer, and the function name contains the tell-tale copy which also implies that you own the buffer. Therefore you can modify it all you want, and must free() it.
Thing is, the result is const because
modifying it will not change the string itself, and the cString is really just meant to be a different representation of the string
it will probably return the same cString "over and over again", as long as the string doesn't change.
Other than that, declaring a result to be const even if the implementation doesn't enforce or require that is something an interface designer can do, maybe because he wants it to be treated that way. And it leaves the path open to optimize things for cases where the "const" is useful.

Pointer to specified number of values

How can I specify that a method should take as parameter a pointer to a location in memory that can hold a specified number of values? For example, if I have:
- (void)doSomethingWith:(int *)values;
I'd like to make it clear that the int * passed in should point to an allocated space in memory that's able to hold 10 such values.
To directly answer your question, use an array argument with a bounds, e.g.:
- (void)takeTenInts:(int[10])array
Which specifies that the method takes an array of 10 integers.
Only problem is the C family of languages do not do bounds checking, so the following is valid:
int a[10], b[5];
[self takeTenInts:a]; // ok
[self takeTenInts:b]; // oops, also ok according to the compiler
So while you are specifying the size, as you wish to do, that specification is not being enforced.
If you wish to enforce the size you can use a struct:
typedef struct
{
int items[10];
} TenInts;
- (void)takeTenInts(TenInts)wrappedArray
Now this doesn't actually enforce the size at all[*], but its as close a you can get with the C family (to which the word "enforcement" is anathema).
If you just wish to know the size, either pass it as an additional argument or use NSArray.
[*] It is not uncommon to see structures in C following the pattern:
typedef struct
{
// some fields
int data[0];
} someStruct;
Such structures are dynamically allocated based on their size (sizeof(someStruct)) plus enough additional space to store sufficient integers (e.g. n * sizeof(int)).
In other words, specifying an array as the last field of a structure does not enforce in anyway that there is space for exactly that number of integers; there may be space for more, or fewer...
Why use "(int *)" when you have the power (and "count") of "NSArray" to work with?
But anyways, looking at this potentially related question, couldn't you just do a "sizeof(values)" to get the size of a statically/globally allocated pointer?
If that doesn't work (which would be in the case of a dynamically allocated array), you really would probably need some kind of "count:" parameter in your "doSomethingWith:" method declaration.
There are a several ways. You could just name the method appropriately:
- (void)doSomethingWithTenInts:(int *)tenInts;
Or you could use a struct:
typedef struct {
int values[10];
} TenInts;
- (void)doSomethingWithTenInts:(TenInts *)tenInts;
Or you could make the user tell you how many ints he is giving you:
- (void)doSomethingWithInts:(int *)ints count:(int)count;

Replace array with another array in C

Out of pure curiosity, I started playing with array's in ways that I have never used before. I tried making a data structure array, and set it equal to another:
typedef struct _test {
float value;
} test;
Simple enough struct, so I tried this:
test struct1[10];
test struct2[20];
struct1 = struct2;
I didn't think this would work, and it didn't even compile. But, this interests me a lot. Is it possible to take an array of 10 and increase the size to 20, while copying the data?
Objective-C
I am actually doing this with Objective-C, so I'd like to hear from the Objective-C people as well. I want to see if it is possible to change the size of struct1 in this file.
#interface Object : NSObject {
test struct1;
}
Remember: This is only out of curiosity, so everything is open to discussion.
Something else that is not exactly pertinent to your question but is interesting nonetheless, is that although arrays cannot be assigned to, structs containing arrays can be assigned to:
struct test
{
float someArray[100];
};
struct test s1 = { /* initialise with some data*/ };
struct test s2 = { /* initialise with some other data */ };
s1 = s2; /* s1's array now contains contents of s2's array */
This also makes it possible to return fixed-length arrays of data from functions (since returning plain arrays is not allowed):
struct test FunctionThatGenerates100Floats(void)
{
struct test result;
for (int i = 0; i < 100; i++)
result.someArray[i] = randomfloat();
return result;
}
As others have said, arrays allocated like that are static, and can not be resized. You have to use pointers (allocating the array with malloc or calloc) to have a resizable array, and then you can use realloc. You must use free to get rid of it (else you'll leak memory). In C99, your array size can be calculated at runtime when its allocated (in C89, its size had to be calculated at compile time), but can't be changed after allocation. In C++, you should use std::vector. I suspect Objective-C has something like C++'s vector.
But if you want to copy data between one array and another in C, use memcpy:
/* void *memcpy(void *dest, const void *src, size_t n)
note that the arrays must not overlap; use memmove if they do */
memcpy(&struct1, &struct2, sizeof(struct1));
That'll only copy the first ten elements, of course, since struct1 is only ten elements long. You could copy the last ten (for example) by changing &struct2 to struct2+10 or &(struct2[10]). In C, of course, not running off the end of the array is your responsibility: memcpy does not check.
You can also you the obvious for loop, but memcpy will often be faster (and should never be slower). This is because the compiler can take advantage of every trick it knows (e.g., it may know how to copy your data 16 bytes at a time, even if each element is only 1 byte wide)
You can't do this in C with static arrays, but you can do it with dynamically allocated arrays. E.g.,
float *struct1, *struct2, *struct3;
if(!(struct1 = malloc(10 * sizeof(float))) {
// there was an error, handle it here
}
if(!(struct2 = realloc(struct1, 20 * sizeof(float))) {
// there was an error, handle it here
// struct1 will still be valid
}
if(!(struct3 = reallocf(struct2, 40 * sizeof(float))) {
// there was an error, handle it here
// struct2 has been free'd
}
In C, I believe that's a good place to use the realloc function. However, it will only work with dynamically allocated arrays. There's no way to change the memory allocated to struct1 by the declaration test struct1[10];.
In C arrays are constants, you can't change their value (that is, their address) at all, and you can't resize them.
Clearly if you declare your array with a fixed size, test struct1[10] then it cannot be resized. What you need to do is to declare it as a pointer:
test *struct1;
Then you must use malloc to allocate the array and can use realloc to resize it whilst preserving the contents of the original array.
struct1 = malloc(10*sizeof(*struct1));
//initialize struct1 ...
test *struct2 = realloc(struct1, 20*sizeof(*struct1));
If you're using Objective C, you know you can just use NSMutableArray, which automatically does the realloc trick to reallocate itself to store however many objects you put in it, up the limit of your memory.
But you're trying to do this with struct? What would that even mean? Suppose you increase the amount of memory available to struct1 in Object. It's still a struct with one member, and doesn't do anything more.
Is the idea to make Object be able to contain an expanded struct?
typedef struct _test2 {
float value;
NSObject *reference;
} test2;
But then you still can't access reference normally, because it's not a known part of Object.
Object *object2;
...
NSLog(#"%#", object2.struct1.reference); // does not compile
If you knew you had one of your modified objects, you could do
Object *object2;
...
NSLog(#"%#", ((test2)(object2.struct1)).reference);
And also you could still presumably pass object2 to anything that expects an Object. It only has any chance of working if struct1 is the last member of Object, and don't mess with subclassing Object either.
Some variety of realloc trick might then work, but I don't think realloc in particular, because that's intended to be used on objects that are allocated with malloc, and the details of what C function is used to allocate objects in not exposed in Objective C, so you shouldn't assume it's malloc. If you override alloc then you might be able to make sure malloc is used.
Also you have to watch out for the fact that it's common in Objective C for more than one pointer to an object to exist. realloc might move an object, which won't be semantically correct unless you correct all the pointers.