Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to interpret objective-c type specifier (e.g. returned by method_copyReturnType())?

Given I have a type specifier as returned by method_copyReturnType(). In the GNU runtime delivered with the GCC there are various methods to work with such a type specifier like objc_sizeof_type(), objc_alignof_type() and others.

When using the Apple runtime there are no such methods.

How can I interpret a type specifier string (e.g. get the size of a type) using the Apple runtime without implementing an if/else or case switch for myself?

[update]

I am not able to use the Apple Foundation.

like image 570
Tilo Prütz Avatar asked Jan 06 '12 09:01

Tilo Prütz


2 Answers

I believe that you're looking for NSGetSizeAndAlignment:

Obtains the actual size and the aligned size of an encoded type.

const char * NSGetSizeAndAlignment (
   const char *typePtr,
   NSUInteger *sizep,
   NSUInteger *alignp
);

Discussion
Obtains the actual size and the aligned size of the first data type represented by typePtr and returns a pointer to the position of the next data type in typePtr.

This is a Foundation function, not part of the base runtime, which is probably why you didn't find it.

UPDATE: Although you didn't initially mention that you're using Cocotron, it is also available there. You can find it in Cocotron's Foundation, in NSObjCRuntime.m.

Obviously, this is much better than rolling your own, since you can trust it to always correctly handle strings generated by its own runtime in the unlikely event that the encoding characters should change.

For some reason, however, it's unable to handle the digit elements of a method signature string (which presumably have something to do with offsets in memory). This improved version, by Mike Ash will do so:

static const char *SizeAndAlignment(const char *str, NSUInteger *sizep, NSUInteger *alignp, int *len)
{
    const char *out = NSGetSizeAndAlignment(str, sizep, alignp);
    if(len)
        *len = out - str;
    while(isdigit(*out))
        out++;
    return out;
}
like image 59
jscs Avatar answered Oct 19 '22 03:10

jscs


afaik, you'll need to bake that info into your binary. just create a function which returns the sizeof and alignof in a struct, supports the types you must support, then call that function (or class method) for the info.

The program below shows you that many of the primitives are just one character. So the bulk of the function's implementation could be a switch.

static void test(SEL sel) {
    Method method = class_getInstanceMethod([NSString class], sel);

    const char* const type = method_copyReturnType(method);

    printf("%s : %s\n", NSStringFromSelector(sel).UTF8String, type);

    free((void*)type);
}

int main(int argc, char *argv[]) {
    @autoreleasepool {

        test(@selector(init));
        test(@selector(superclass));
        test(@selector(isEqual:));
        test(@selector(length));

        return 0;
  }
}

and you could then use this as a starting point:

typedef struct t_pair_alignof_sizeof {
    size_t align;
    size_t size;
} t_pair_alignof_sizeof;

static t_pair_alignof_sizeof MakeAlignOfSizeOf(size_t align, size_t size) {
    t_pair_alignof_sizeof ret = {align, size};
    return ret;
}

static t_pair_alignof_sizeof test2(SEL sel) {
    Method method = class_getInstanceMethod([NSString class], sel);
    const char* const type = method_copyReturnType(method);
    const size_t length = strlen(type);

    if (1U == length) {
        switch (type[0]) {
            case '@' :
                return MakeAlignOfSizeOf(__alignof__(id), sizeof(id));
            case '#' :
                return MakeAlignOfSizeOf(__alignof__(Class), sizeof(Class));
            case 'c' :
                return MakeAlignOfSizeOf(__alignof__(signed char), sizeof(signed char));
            ...
like image 23
justin Avatar answered Oct 19 '22 04:10

justin