# Type Encodings

By [Mattt](https://nshipster.com/authors/mattt).
Published 2013-02-04.
Canonical URL: <https://nshipster.com/type-encodings>

From [number stations](https://en.wikipedia.org/wiki/Numbers_station) and [numerology](https://en.wikipedia.org/wiki/Numerology) to [hieroglyphs](https://en.wikipedia.org/wiki/Egyptian_hieroglyphs) and [hobo codes](https://en.wikipedia.org/wiki/Hobo#Hobo_.28sign.29_code), there is something truly fascinating about finding meaning that hides in plain sight. Though hidden messages in and of themselves are rarely useful or particularly interesting, it’s the thrill of the hunt that piques our deepest curiosities.

It is in this spirit that we take a look at [Objective-C Type Encodings](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html) in this week’s edition of NSHipster.

---

[Last week](https://nshipster.com/nsvalue/), in a discussion about `NSValue`, there was mention of `+valueWithBytes:objCType:`, whose second parameter should be created with the Objective-C `@encode()` compiler directive.

`@encode`, one of the [`@` Compiler Directives](https://nshipster.com/at-compiler-directives/), returns a C string that encodes the internal representation of a given type (e.g., `@encode(int)` → `i`), similar to the `typeof` operator (a GNU C extension, standardized in C23). Apple’s Objective-C runtime uses type encodings internally to help facilitate message dispatching.

Here’s a rundown of all of the different Objective-C Type Encodings:

| Code | Meaning |
| - | - |
| `c` | A `char` |
| `i` | An `int` |
| `s` | A `short` |
| `l` | A `long`. `l` is treated as a 32-bit quantity on 64-bit programs. |
| `q` | A `long long` |
| `C` | An `unsigned char` |
| `I` | An `unsigned int` |
| `S` | An `unsigned short` |
| `L` | An `unsigned long` |
| `Q` | An `unsigned long long` |
| `f` | A `float` |
| `d` | A `double` |
| `B` | A C++ `bool` or a C99 `_Bool` |
| `v` | A `void` |
| `*` | A character string (`char *`) |
| `@` | An object (whether statically typed or typed `id`) |
| `#` | A class object (`Class`) |
| `:` | A method selector (`SEL`) |
| \[_array type_] | An array |
| {_name=type..._} | A structure |
| (_name_=_type..._) | A union |
| `b`num | A bit field of _num_ bits |
| `^`type | A pointer to _type_ |
| `?` | An unknown type (among other things, this code is used for function pointers) |

Charts are fine, but experimenting in code is even better:

```objc
NSLog(@"int        : %s", @encode(int));
NSLog(@"float      : %s", @encode(float));
NSLog(@"float *    : %s", @encode(float*));
NSLog(@"char       : %s", @encode(char));
NSLog(@"char *     : %s", @encode(char *));
NSLog(@"BOOL       : %s", @encode(BOOL));
NSLog(@"void       : %s", @encode(void));
NSLog(@"void *     : %s", @encode(void *));

NSLog(@"NSObject * : %s", @encode(NSObject *));
NSLog(@"NSObject   : %s", @encode(NSObject));
NSLog(@"[NSObject] : %s", @encode(typeof([NSObject class])));
NSLog(@"NSError ** : %s", @encode(typeof(NSError **)));

int intArray[5] = {1, 2, 3, 4, 5};
NSLog(@"int[]      : %s", @encode(typeof(intArray)));

float floatArray[3] = {0.1f, 0.2f, 0.3f};
NSLog(@"float[]    : %s", @encode(typeof(floatArray)));

typedef struct _struct {
    short a;
    long long b;
    unsigned long long c;
} Struct;
NSLog(@"struct     : %s", @encode(typeof(Struct)));
```

Result:

| Type | Encoding |
| - | - |
| `int` | `i` |
| `float` | `f` |
| `float *` | `^f` |
| `char` | `c` |
| `char *` | `*` |
| `BOOL` | `c` or `B` |
| `void` | `v` |
| `void *` | `^v` |
| `NSObject *` | `@` |
| `NSObject` | `{NSObject=#}` |
| `[NSObject]` | `#` |
| `NSError **` | `^@` |
| `int[]` | `[5i]` |
| `float[]` | `[3f]` |
| `struct` | `{_struct=sqQ}` |

There are some interesting takeaways from this:

- Whereas the standard encoding for pointers is a preceding `^`, `char *` gets its own code: `*`. This makes sense conceptually, as C strings are thought to be entities in and of themselves, rather than a pointer to something else.
- `BOOL` is `c`, rather than `i`, as one might expect. Reason being, `char` is smaller than an `int`, and when Objective-C was originally designed in the 80’s, bits (much like the dollar) were more valuable than they are today. `BOOL` is specifically a `signed char` (even if `-funsigned-char` is set), to ensure a consistent type between compilers, since `char` could be either `signed` or `unsigned`. That’s still true on Intel-based Macs, but on 64-bit iOS and on Macs with Apple silicon, `BOOL` is C’s `bool`, and `@encode(BOOL)` returns `B`.
- Passing `[NSObject class]` yields `#`. However, passing `NSObject` directly yields a struct named `NSObject` with a single class field: `isa`, which `NSObject` instances have to signify their type.

## Method Encodings

As mentioned in Apple’s [“Objective-C Runtime Programming Guide”](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html), there are a handful of type encodings that are used internally, but cannot be returned with `@encode`.

These are the type qualifiers for methods declared in a protocol:

| Code | Meaning |
| - | - |
| `r` | `const` |
| `n` | `in` |
| `N` | `inout` |
| `o` | `out` |
| `O` | `bycopy` |
| `R` | `byref` |
| `V` | `oneway` |

For anyone familiar with [NSDistantObject](https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDistantObject_Class/Reference/Reference.html), you’ll doubtless recognize these as a vestige of [Distributed Objects](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DistrObjects/DistrObjects.html#//apple_ref/doc/uid/10000102i).

Although DO has fallen out of fashion in the age of iOS, it was an interprocess messaging protocol used between Cocoa applications–even running on different machines on the network. Under these constraints, there were benefits to be had from the additional context.

For example, parameters in distributed object messages were passed as proxies by default. In situations where proxying would be unnecessarily inefficient, the `bycopy` qualifier could be added to make sure a full copy of the object was sent. Also by default, parameters were `inout`, signifying that objects needed to be sent back and forth when sending the message. By specifying a parameter as `in` or `out` instead, the application could avoid the round-trip overhead.

---

So what do we gain from our newfound understanding of Objective-C Type Encodings? Honestly, not that much (unless you’re doing any crazy metaprogramming).

But as we said from the very outset, there is wisdom in the pursuit of deciphering secret messages.

Looking at type encodings reveals details about Objective-C runtime internals, which is a noble pursuit in and of itself. Go further down the rabbit hole, and we come to the secret history of Distributed Objects, and the obscure parameter qualifiers that [still linger around to this day](https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/Reference/Reference.html%23jumpTo_22).
