Next article: Friday Q&A 2009-07-03: Type Specifiers in C, Part 2
Previous article: Friday Q&A 2009-06-19: Mac OS X Process Memory Statistics
Tags: c fridayqna
Welcome back to another warm and fuzzy edition of Friday Q&A. This week I'm going to discuss the use of type qualifiers in C, a subject suggested by Nate Vander Wilt.
What They Are
The first thing is to talk about what type qualifiers actually are. In short, they're a keyword which can be used to modify the properties of an arbitrary type. The most common one is
const. Type qualifiers should not be confused with keywords which modify the storage of a particular variable. Those are called storage specifiers.
Let me illustrate with an example:
static const int *x;
static is a storage specifier. It modifies the variable
x to change how
x is actually stored. The
const keyword is a type qualifier, which modifies the
By way of illustration, it makes perfect sense to use
const in a
typedef, like so:
typedef const int MyConstInt;
staticin this way, because
staticis not part of the type:
typedef static int MyStaticInt; // will not compile, does not make sense!
This week I will discuss
restrict, and I'll finish up next week with a discussion of
The const qualifier is far and away the most common and the most useful of the three. Its meaning is very easy to understand: when applied to a type,
const makes that type become read-only.
There are several places where
const can be useful:
- On a function pointer parameter. A
constfunction pointer parameter means that the function won't modify the value that the pointer points to. For example, look at the standard
strchrfunction. The first parameter is declared of type
const char *, because this function only reads the string, and doesn't modify it. This is a useful thing to do with your own code as well when taking pointer parameters that won't be modified.
- On a function pointer return value. Used here,
constindicates that the data being returned is read-only and the caller is not allowed to modify it. For example, the
-[NSString UTF8String]method in Cocoa returns a
const char *. This means you can use the data but you're not allowed to write to it. The data may be a pointer to some kind of internal storage or cache, and the
constis used to enforce access to make this useful.
- On a local or global pointer variable. When used here,
constindicates that this pointer can't be used to modify its contents. This can be useful to preserve correctness when you know that your use is read-only, but is most often useful to shut up the compiler when accessing
constreturn values from functions that return
constpointers as in #2.
- On a local or global non-pointer variable. This is handy to declare a compile-time constant. For example,
const int kMeaning = 42;declares a constant. The
consthere will help prevent you from changing this value by accident, and may also allow the compiler to do some optimizations that otherwise would not be possible.
Since this is a heavily Mac-centric blog, I also want to briefly discuss
const as it applies to Objective-C. In particular, you should never declare an Objective-C object type as
const. For example, this is not a good way to enforce the immutability of an
const NSString *immutableNSStringPointer;
constmeans here is that you can't use
immutableNSStringPointerto modify the memory at that location. But the immutability of an
NSStringis part of the API contract only. Nothing says that the memory of an
NSStringcan't be modified, only that the semantic contents of the
NSStringcan't be modified. For example,
NSStringmight have some internal caches that get updated, but which don't affect the conceptual contents of the string. Changing those caches would violate the
constrequirement, but not the immutability of the
More concretely, if you declare a variable like this and then try to use it anywhere, you'll get a huge number of useless warnings about violating the
constness of your variable.
What if you want a constant NSString pointer? Not a pointer to a constant NSString, but a constant pointer, one which can't be changed. The NSString equivalent of the
const int kMeaning = 42; example from above. This can easily be done, you just have to apply the
const to the variable directly, by altering its position:
NSString * const kConstantStringPointer = @"hello, world";
restrictkeyword is new in C99. (The other two date from C89.) This one is purely for the purposes of optimization. That fact, combined with the fact that it's kind of hard to understand, means that this keyword is extremely rare to see and even more rare to actually use.
So what does
restrict mean, exactly? It's actually pretty simple: when a pointer is declared with
restrict, it tells the compiler that this is the only pointer which will be accessing a particular chunk of memory in that scope.
But what does that mean? Consider the following code:
char *src, *dst; ... for(int i = 0; i < len; i++) dst[i] = src[i];
src + 1. Each time the assignment is made, it also alters the value that will be used for the next iteration of the loop. Unless the compiler can rule out this possibility (which is extremely difficult to do automatically) it's forced to generate very slow code.
This is where the
restrict keyword comes in. By declaring
restrict, you tell the compiler that you are personally guaranteeing that they won't point into the same block of memory, and thus that the compiler should feel free to generate nice, fast code for this loop.
It's unlikely that you'll have occasion to use
restrict in your own code. However you may encounter it elsewhere. For example, here is the prototype for the
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
memcpy'sAPI contract: it only works on blocks which don't overlap. (The
memmovefunction is provided for blocks which potentially do overlap.) Previously this was only expressed in the documentation, but using
restrictit can actually be expressed right in the code.
That brings us to the end of Part 1. Now you know what
restrict mean and how to use them. The
const can be very useful and every C programmer should know how to use it. The
restrict keyword is mostly useless unless you're writing certain kinds of highly optimized code, but it's still good to know the basics.
Next week I'll discuss the
volatile keyword. It sits in an interesting middle ground in between
restrict: not nearly as useful or common as the former, but much more widely used and marginally more useful than the latter. It's also very frequently misunderstood and misused. For all the details on what it does, how to use it, and (most importantly) how not to use it, check back next week.
And as always, Friday Q&A runs on your ideas, so send them in! If you have a subject that you would like to see discussed here, post it in the comments or e-mail it to me directly.
Comments RSS feed for this page
Add your thoughts, post a comment:
Spam and off-topic posts will be deleted without notice. Culprits may be publicly humiliated at my sole discretion.