Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C; typedef objc_object as substitute for id without pointer;

In Objective-C id is a typedef:

typedef struct objc_object {
     Class isa;
} *id;

So I can declare (and initialize) a variable e.g. like this:

// using id
id po_one = @"one";

Compiles fine.

Since I name my types in an own scheme and since I dislike the implied pointer in the id typedef I want to add an own typedef (with O for object) like this:

typedef struct objc_object O;

So a variable declaration (with initialization) could look like:

// using O
O * po_two = @"two";

This compiles with a warning:

Initialization from incompatible pointer type

As far as I understand typedefs I thought that the latter should be equivalent to:

// using struct objc_object
struct objc_object * po_three = @"three";

Which again compiles fine.

It's astonishing that:

po_two = po_one;
po_two = po_three;

both compile without warnings.

So I tried:

typedef struct objc_object * PO;

to see whether it works without warning if I include the pointer (being exactly the thing I want to avoid - so just for test reasons) to see whether a typedef outside of the structure definition works differently to a typedef in the structure definition (which is the definition of id in this case).

// using PO
PO po_four = @"four";

That also works fine.

If I use:

#define O struct objc_object

the construct using O again compiles without warning.

But I prefer to use typedefs instead of a defines whenever possible.

I'm puzzled. What is my misunderstanding with typedefs?

like image 281
carpetemporem Avatar asked Nov 05 '22 03:11

carpetemporem


1 Answers

I'm not an expert of compilers, so probably a real expert can give you a better answer. In any case, based on my knowledge, when a compiler does type checking, it bases this check on the "parse tree", which generates a sort of table for all possible data type structures, and check if two definitions point to the same row in the table. So it works by fetching symbols and type definitions from this table and comparing them. Now "struct objc_object" is one of these data structures. Then, when id is defined, it generates another entry: "id --> struct objc_object *". The po_three definition leads to the same reference: "struct objc_object *" (infact "=" has lowest precedence). The same happens for po_four, because PO leads by definition to the same reference, again (PO --> struct objc_object *). When you use the definition with #define, thanks to preprocessing you're still referencing "struct objc_object *". But when you use

O * po_two = @"two"
you're in fact trying to match one type which is "id" (@"two"), that is "struct objc_object *" and another one which is a pointer to "struct objc_object" but even if logically they are the same they don't lead to the same reference in the table. The reason is because "O" type has been defined yet, so po_two is simply stored in the symbol table as a pointer to "O" and "O --> struct objc_object". And that's the reason of the warning: po_two is a pointer to something different than @"two".

I have a curiosity: have you tried to plot the symbol table using "nm"?

like image 141
viggio24 Avatar answered Nov 15 '22 04:11

viggio24