Archive for the 'C' Category

A simple way to make your NSLogs and NSAsserts more informative

Wednesday, June 13th, 2007

OK, so I'm not totally radio-silent. I learned about this in a WWDC session, but since it's already public API in Tiger (actually, it's a GCC extension), I can talk about it.

It's a built-in macro called __PRETTY_FUNCTION__. This is a fully-qualified human-readable signature of the function you're in. The GCC docs don't mention this part, but it even works in Objective-C, in addition to C++ and plain C. Here's a test app, containing this code:

@implementation Blah(blah)
- (void)blah {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}
@end

And the output:

2007-06-14 07:50:37.733 printmethod[1800] -[Blah(blah) blah]

Notice that it includes the class name, category name (if any), and method selector.

Note that that's a C-string, not an NSCFString. Be sure to set up your format string accordingly.

How do I swap thy bytes? Let me count the ways

Saturday, April 28th, 2007
  1. swab

    swab(3) is a function that copies some bytes from one location to another, swapping each pair of bytes during the copy. Handy for structures.

    It has a feature that isn't mentioned in the Darwin manpage for swab: If you pass a negative size, it does not swap. I have no idea why this magic behavior was added; if you want a swab that doesn't swap bytes, just use bcopy. I shake my head at this use of a magic argument.

  2. ntohs, htons, ntohl, htonl

    These four functions swap the bytes of a 16-bit (‘s’) or 32-bit (‘l’, in ignorance of LP64) integer and return the transformed value.

    They are mainly used in network-I/O contexts, as they transform between network byte order (big-endian) and host byte order (whatever you're running). But there's nothing stopping you from using them for any other 16-bit/32-bit integral byte-swapping.

  3. OSByteOrder (Darwin)

    The Darwin kernel provides a number of handy-dandy macros for byte-swapping:

    • OSSwap{Const}?Int{16,32,64}
    • OSSwap{Host,Big,Little}To{Host,Big,Little}{Const}?Int{16,32,64}

    The {Host,Big,Little}To{Host,Big,Little} functions swap conditionally; the others always swap.

    According to the Universal Binary Programming Guidelines, it is safe to use these in applications.

  4. Core Foundation

    CF's Byte-Order Utilities provide the same facilities as OSByteOrder, with a couple of twists:

    • The implementation uses assembly language when the environment is GCC on either PowerPC or x86. This is theoretically faster than OSByteOrder's pure-C implementation. (CF falls back on pure C in all other environments.)
    • CF adds support for byte-swapping 32-bit and 64-bit floating-point numbers.
  5. Foundation

    Foundation's byte-order functions bear all the same capabilities as the CF Byte-Order Utilities. In fact, they are implemented with them.

  6. NeXT byte-order utilities

    These utilities are equivalent to the Foundation functions, except that they are implemented using the OSByteOrder utilities. They are declared in <architecture/byte_order.h>.

  7. Core Endian

    Core Endian logo that I made up.

    I think that the “Core Endian” name itself is new in Panther. Three functions in the API have a “CoreEndian” prefix, and are marked as new in Panther, whereas the others have simply “Endian”, and are marked as having existed since 10.0. This suggests to me that the entire API was branded “Core Endian” in 10.3, with the older functions subsumed by it.

    The new functions have to do with “flipper” callbacks, which you can install so that things like Apple Event Manager can DTRT with your custom data types. The older functions are plain byte-swapping utilities, just like all the other APIs described here, and exist mainly for the benefit of QuickTime users (they exist on Windows, too, through QuickTime).

Guess the bug!

Saturday, March 31st, 2007

UPDATE: NO BUG! Serves me right for not testing a programming challenge before posting it. Thanks, Evan.

a = 42, b = 100;

Before you type “error on line 1”: No, it's not a compilation error. The above code is legal, just wrong. The task before you is to explain how. ☺

Please do not use %x for pointers

Tuesday, January 23rd, 2007

I often see code like this:

printf("Address of foo: %x\n", &foo);

The intent here is to print the address in hexadecimal format. Good plan; bad execution.

First, here's one possible output:

Address of foo: 123456

Is this decimal (%u), hex (%x), or octal (%o)? I can't tell from the output; for all I know, the person who wrote that line is a real newbie and used %i or %d. (That would be even worse for really high addresses, as they will then be formatted as negative numbers.)

So the author changes the line to:

printf("Address of foo: 0x%x\n", &foo);

Now the output has the 0x prefix, making clear that it's hex, but there's still a bug here. The bug is that %x is not the correct formatter for pointers.

The type expected by %x is unsigned int. For the past decade or so, this has not been a problem because on all PCs, including Macs, the size of a pointer has been equal to the size of an int.

But over the past couple years and the next couple years, there's a transition underway to LP64, wherein long ints and pointers are 64-bit. Plain ints won't be; they'll still be 32 bits. This means that you'll get funky results, and possibly crashes (with %s, %n, and %@), if you're using %x for your pointers.

You could use %lx (unsigned long int), but it's still the wrong type. There is a formatter specifically for pointers: %p. It even provides the “0x” prefix for you.

printf("Address of foo: %p\n", &foo);

Address of foo: 0x1e240

So, in order to make your code both more stable and more future-proof, please use %p, not %x or %lx, for formatting your pointers.

Why you should use #pragma mark

Saturday, January 20th, 2007

It's a minute and a half, and it's 200 K, and you'll need QuickTime 7 to watch it.


pragma mark at work in Xcode's editor.

Useful as #pragma mark is, I wouldn't recommend it for cross-platform code. GCC's documentation of #pragma mark seems to suggest that it's Darwin-only.

On initializing static variables

Thursday, January 4th, 2007

Did you know that you don't have to initialize static variables? (If you've done any Cocoa programming, you know that statics are commonly treated as class ivars, most commonly to hold singleton instances.)

Quoth C99 (§6.7.8 paragraph 10):

… If an object that has static storage duration is not initialized explicitly, then:

  • if it has pointer type, it is initialized to a null pointer;
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
  • if it is an aggregate [array or structure —PRH], every member is initialized (recursively) according to these rules;
  • if it is a union, the first named member is initialized (recursively) according to these rules.

And I've prepared a test app that shows that gcc 4.0.1 on OS X 10.4.8 does seem to comply with this handy part of the standard.

Happy not-initializing!

Wanted for abuse of operators

Saturday, December 2nd, 2006

From the stock app delegate in Apple's Core Data application template:

[managedObjectContext release], managedObjectContext = nil; [persistentStoreCoordinator release], persistentStoreCoordinator = nil; [managedObjectModel release], managedObjectModel = nil;

And in case you were wondering how Apple could possibly ship code that doesn't even compile in the app templates…

… that's legal code.

Yes, there is a comma operator, and that's what's at work there. There is a warning (-release returns void, whereas assignment of nil returns id, so the types are mismatched, which GCC doesn't like), but the code is legal.

Legal doesn't always mean correct, however. The comma operator is supposed to be used for things like this:

printf("%s\n", (-‍-argc, *++argv));

Though in modern usage it is out of favor, replaced on sight with less obfuscative code:

printf("%s\n", *++argv); -‍-argc;

printf("%s\n", argv[idx++]);

It is not for performing a void function call followed by an assignment. A void expression should never appear in a comma expression. The code would be greatly improved by replacing the comma with a semicolon, dividing each statement into the two statements that it should be.

Fun with printf

Friday, November 17th, 2006

fprintf(usageOutputFile, "… (200 pixels across, 50% of height).\n");

Output:

… (200 pixels across, 5027777772734f height).

Guess the bug!

I feel good about Mac open source

Monday, October 2nd, 2006

(I've had this brewing in a VoodooPad page for some months now, and have finally gotten around to implementing it.)

I feel good about Mac open source.

Many of my fellow Mac programmers have made reusable source code available under free licenses, such that any other programmer can use it in their applications. This abundant generosity impresses me, and at this point has moved me to build a catalog of this code.

It's organized by author name and by program name. It's not just applications, though; plain classes are also listed, as are useful-looking images (such as my own plus/minus button images).

Enjoy.

UPDATE 19:07: This is actually a duplicate post of an earlier draft. I'll see about moving the comments over to the correct post. In the meantime, if you have any further comments, please post them over there.

UPDATE 19:43: Done. I ended up just renaming this post (dropped “-2” from the post slug; you'll need to update any links to this post) and removing the duplicate post.

Making GCC use proper quote marks

Tuesday, September 19th, 2006

When you build a program in Xcode, you may have noticed that error messages from GCC look like this:

error.c: In function `main':
error.c:2: warning: implicit declaration of function `pirntf'

This shouldn't happen on a modern operating system with modern text capabilities. Fortunately, it is easy enough to make it do the Right Thing, which is to use Unicode quote marks.

First, figure out the correct ISO 639-1 language code for your preferred language. I use English, so mine is “en”. The Library of Congress has a list of ISO 639-1 language codes. In addition, you may want to append a region code; I use American English, so mine is “US”. These should be separated by an underscore; my full language specifier, then, is “en_US”.

Then, append “.UTF-8” to this (= “en_US.UTF-8”), and set it in your LC_ALL environment variable. You can do this by adding this variable to $HOME/.MacOSX/environment.plist. If you don't already have one, you can create it with Property List Editor; you will need to move it to the proper location with Terminal. Either way, you will then need to logout and login.

GCC will then use nice Unicode quote marks in its output:

error.c: In function ‘main’:
error.c:2: warning: implicit declaration of function ‘pirntf’

There's extra work to do if you also invoke builds from Terminal or xterm (whether you use xcodebuild, make, or gcc directly).

Terminal

  1. Right-click on any Terminal window and choose “Window Settings…”.
  2. Switch to the “Display” pane.
  3. Set the character set encoding to UTF-8.
  4. Turn off “wide glyphs for Japanese/Chinese/etc.”.
  5. Click “Use Settings as Defaults”.

xterm

  1. In your .Xdefaults file, add these lines:

    xterm*font:        -*-clean-medium-r-*-*-12-*-*-*-*-*-iso10646-*
    xterm*boldFont:    -*-clean-bold-r-*-*-12-*-*-*-*-*-*-*
    xterm*utf8:        1

    Note that you can specify any font for the two font values; however, “clean”'s Unicode version only exists in plain, not boldface.

Parsing the preprocessor

Thursday, June 15th, 2006

If you've ever run GCC's preprocessor alone and looked at its output, you've seen lines like these:

# 1 "/usr/include/sys/types.h"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "/usr/include/sys/types.h"
# 66 "/usr/include/sys/types.h"
# 1 "/usr/include/sys/appleapiopts.h" 1 3 4
# 67 "/usr/include/sys/types.h" 2


# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 70 "/usr/include/sys/types.h" 2

And you probably wondered what all that means. Here's your secret decoder ring.

First, these are called "line markers" in libcpp. The format of a line marker is:

  1. A line number
  2. The path to the relevant file
  3. Flags

The flag values are:

1
Push (enter) header
2
Pop (leave) header
3
This is a system header (determined by these rules with this modification)
4
Requires extern "C" protection (determined by the same rules as above); never found without 3

Note that a pop applies to the header above (in the include stack) the one referenced in the marker.

Example:

# 66 "/usr/include/sys/types.h"
# 1 "/usr/include/sys/appleapiopts.h" 1 3 4
# 67 "/usr/include/sys/types.h" 2
  1. Fast-forward to line 66 of <sys/types.h> (nothing interesting occurs before this line).
  2. Enter <sys/appleapiopts.h>. Everything from this point until the next marker is from that header. Note that this header is a system header (3) and requires extern "C" protection (4).
  3. As it turns out, nothing interesting happened there. So the very next line is a pop marker: <sys/appleapiopts.h> is popped, so now we're back in <sys/types.h>, now on line 67 (the line after the #include <sys/appleapiopts.h>).

The relevant code in libcpp is in directives.c. The function that parses line markers (presumably used by the compiler rather than the preprocessor itself; the preprocessor generates them) is do_linemarker. Additional include-related code is in files.c.

UPDATE 23:24 PDT: Beware of pragmas. Seems obvious now, but I didn't think of it earlier: The preprocessor leaves #pragma directives untouched, being that they're for the compiler rather than the preprocessor. So if you're only looking for line markers, you may get tripped up if you don't properly handle/ignore a pragma.

Technorati tags: , , .

Within epsilon of perfect

Monday, March 27th, 2006

(Title taken from my own assessment of my spelling.)

It's been known for awhile that rather than directly comparing two floating-point numbers, you should instead subtract the larger from the smaller and compare the difference to some epsilon value. The reason for this is that two numbers might be very very similar, but not exactly equal. “Epsilon” in a mathematical sense means “minimum precision that you care about”. The epsilon value for money, for example, is usually 0.01 — differences lower than this are thrown away.

So of course I went scrounging in the headers, found macros named FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON, and recommended to all my programmer friends that they use these constants for comparisons of floating-point values rather than == and !=.

From time to time, facts just float up to the top of my head for no obvious reason. I have a sheet taped to my wall called “Word of the Day”; when a word pops into my head like this, completely unrelated to any previous thoughts, I write it down on that sheet to look up later. I consider this a more advanced (if slow) form of self-education. They might be long-forgotten memories, or something else; I don't know, I just write them down and look them up.

About half an hour ago, this happened to me again. Except this time, the thought was definitely a memory, of something I'd read in float.h:

/* The difference between 1 and the least value greater than 1 that is
   representable in the given floating point type, b**1-p.  */

Another thought had bubbled up with this, and it was an epiphany: Technically, this means that the expression x != (x + FOO_EPSILON) should evaluate to 1. In other words, subtracting from FOO_EPSILON isn't necessary.

So, as is my wont, I wrote a test app. Sure enough, that expression does evaluate to 1.

So forget what I said. x != y is directly equivalent to comparison against FOO_EPSILON, and it's easier to read, too. So just use that.

Technorati tags: , .

Pointer talk 1.2

Thursday, January 19th, 2006

the new version of the pointer talk is live.

Declarators are fun! Part II

Sunday, January 8th, 2006

One more:

6.2.5[28]:

EXAMPLE 2 The type designated as “struct tag (*[5])(float)” has type “array of pointer to function returning struct tag”. The array has length five and the function has a single parameter of type float. Its type category is array.

Declarators are fun!

Saturday, January 7th, 2006

I was reading the C99 standard (because, you know, I'm Bored) and found a couple of interesting tidbits. Read on and see…

6.7.6[3]:

EXAMPLE The constructions

  1. int
  2. int *
  3. int *[3]
  4. int (*)[3]
  5. int (*)[*]
  6. int *()
  7. int (*)(void)
  8. int (*const [])(unsigned int, ...)

name respectively the types (a) int, (b) pointer to int, (c) array of three pointers to int, (d) pointer to an array of three ints, (e) pointer to a variable length array of an unspecified number of ints, (f) function with no parameter specification returning a pointer to int, (g) pointer to function with no parameters returning an int, and (h) array of an unspecified number of constant pointers to functions, each with one parameter that has type unsigned int and an unspecified number of other parameters, returning an int.

6.7.5.3[16]:

EXAMPLE 1 The declaration

int f(void), *fip(), (*pfi)();

declares a function f with no parameters returning an int, a function fip with no parameter specification returning a pointer to an int, and a pointer pfi to a function with no parameter specification returning an int. …

See also part II.

The pointer talk, version 1.1

Sunday, January 1st, 2006
Bigger and better. The old version is still available in a zip file, if you want it.

My home page, and the pointers tutorial

Thursday, December 22nd, 2005

As some of you know, I used to have a website, but when Colin's server ate its own hard disk, that went away. I still have the backups, fortunately, but you can't get to those from the internet.

As some of you also know, I have a Yahoo! account.

As probably a lot of you know, Yahoo! bought GeoCities a long while back.

So for now, until I get some better hosting lined up (suggestions?), I've set up web space at GeoCities. The new Domain of the Bored. Yes, there's nothing there yet.

Except for the ever-popular pointers tutorial.

Several times now, I've given people a one-on-one tutorial on the nature and care and feeding of pointers in C. This spiked this month, with me giving the talk twice. So I decided to write it up and make a webpage out of it.

Enjoy the pointer talk.

UPDATE 2006-08-27: Updated the pointer-tutorial link, though I (intentionally) left the GeoCities-homepage link alone. Also added a forward link to my blog post on hosting.