Type qualifiers are heavily used in C and Objective C. In C99 there are three
type qualifiers: const
, restrict
, and volatile
. In objective C,
Apple introduced __weak
, __strong
, __unsafe_unretained
, and
__autoreleasing
for automatic reference counting.
It is easy to get confused with complicated type qualifiers. For example:
1
|
|
In this post I’ll go through what type qualifiers are, and how do we read and write it in correct way.
Names and definitions
Type qualifiers should not be confused with storage specifiers like static
auto
, extern
and register
. To illustrate this, allow me to use Mike Ash’s
example:
1
|
|
Here, static
is a storage specifier to tell complier how x
is stored, and
const
is a type qualifier to tell complier the type of x is read-only
data. Since const
is part of the type, you can write:
1
|
|
but you cannot write:
1
|
|
This is because static
is not part of the type.
You might wonder: is __block
a type qualifier or storage specifier? The
clang block language spec said that it is a storage qualifier.
Don’t get confused. __block
is a storage qualifer/specifer which modifies
how variable is stored. For more curious on __block
, you can check out my
previous post Block byref internals.
ARC ownership qualifiers
What about __strong
, __weak
, __unsafe_unretained
, and __autoreleasing
?
You can use it with typedef
, and they are truly part of the type. However, they
are a bit different from C type qualifiers. ARC generated code have an runtime
API supports it. You can manually use some of those: objc_storeWeak
,
objc_destroyWeak
…etc. In Clang specification, these qualifiers are named
ownership qualifiers. Luckily, they share the same rule of type
qualifiers.
The grammar
C declaration can be really complicated. In this section I’ll just cover the basics and the most commonly seen ones.
- Rule 1: find the identifier (the variable), read from right to left.
1 2 3 |
|
When there is a type qualifier, it applies to its immediate left:
1 2 3 4 |
|
- Rule 2: If next to type specifier, it applies to type-specifier
1 2 |
|
- Rule 3: If there are parenthesis or bracelets, reorder it to postfix form:
1 2 3 4 |
|
For more curious, checkout Deciphering Complex C Declarations and cdecl.
volatile, restrict
volatile
Every reference to the variable will reload the contents from memory rather than take advantage of situations where a copy can be in a register.
The volatile
qualifier maintains consistency of memory access to data objects.
Volatile variable are read from memory each time their values is needed, and
writen back to memory each time they are changed. However, volatile variables
are not automic. If you want to write thread safe operation, you can write
something like:
1 2 3 4 |
|
This is a function that is thread and multiprocessor safe to swap/update an integer. Objective-C runtime uses these functions defined in OSAtomic.h to manage retain counts.
restrict
restrict
is a keyword purely for the purpose of optimization.
In the C programming language, as of the C99 standard, restrict is a keyword that can be used in pointer declarations. The restrict keyword is a declaration of intent given by the programmer to the compiler. It says that for the lifetime of the pointer, only it or a value directly derived from it (such as
pointer + 1
) will be used to access the object to which it points. This limits the effects of pointer aliasing, aiding caching optimizations.
restrict
is a qualifier for pointers. It claims that the memory that pointer
points to can only be accessed by this pointer. Consider this case:
1 2 3 |
|
If the *dst
overlapped with *src
, compiler can only generate code that load a
small piece of memory and operate it once at a time. Fortran does not have this
problem because it does not have pointers. Thus Fortran can do ambitious optimization
to load a big chunck of memory and operate it all at once. restrict
is a new
keyword defined in C99 to address this problem. The original code can be
rewritten as:
1
|
|
and compiler can optimize this code like Fortran does!
Note that restrict
is a type qualifier for pointers.
1 2 3 |
|
ARC ownership qualifiers
If you understand all the above, then Objective-C Automatic Reference Counting qualifiers should be easy to you! Here is the definition from Apple:
__strong
is the default. An object remains alive as long as there is a strong pointer to it.__weak
specifies a reference that does not keep the referenced object alive. A weak reference is set tonil
when there are no strong references to the object.__unsafe_unretained
specifies a reference that does not keep the referenced object alive and is not set tonil
when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.__autoreleasing
is used to denote arguments that are passed by reference(id *)
and are autoreleased on return.
All ownership qualifiers should decorate on Objective-C object pointers.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
For more curious on why do we need to write verbose code for CGColor
, you can
take a look at Big Nerd Ranch’s
ARC Gotcha – Unexpectedly Short Lifetimes and Amatten’s
ARC Best Practices.