Quickie: Qsort Compare Func Trick

Sitting at a bus stop in Lima, compiler running in the background, got a few minutes to kill. Quickie time!

I came across this trick for qsort in some code at work that August wrote. Cool trick, simple, can’t believe I haven’t seen this before. It’s probably in K&R and a million FAQ’s and so on, but I missed it anyway. In a Google for “qsort compare function sample” you get a mix of both tricks that come up.

Here’s a basic qsort compare proc that I pulled from one of the samples I found:

int sortFunction(const void *a, const void *b) { int intOne = *((int*)a); int intTwo = *((int*)b); if (intOne < intTwo) return -1; if (intOne == intTwo) return 0; return 1; }

Pretty straightforward, but here’s a smaller and quicker version!

int sortFunction(const void *a, const void *b) { int intOne = *((int*)a); int intTwo = *((int*)b); return intOne - intTwo; }

No branching is required. This is much faster as well as being shorter. This is great when you are sorting by multiple keys at once – you only need to test for 0 before moving on to the next sub-key, otherwise return the difference you already have.

Some important notes:

  • This obviously doesn’t work on non-numeric types like a string. Still have to do those the old way.
  • In C++ if you are using the std library you should use std::sort, which only requires a single < compare (unlike qsort’s troika of <0, 0, or >0 returns). Does not use callbacks, and inlines your comparison proc. Much faster than qsort.
  • If you do use this trick put a comment in the code mentioning it’s on purpose! At first it will look like a bug to a casual observer.

UPDATE: (10/10/2009)

Commenter Arseny points out that this can be dangerous! Put a big comment on the sort function noting that the caller needs to keep in mind the range of data being used.

It’s a good idea to put in a simple assert that tests for this.

I’d still not shy away from the technique. The boundary conditions are very far out, and unlikely for most scenarios. An assert would put my mind at ease.

2 comments on this post.
  1. Arseny Kapoulkine:

    I’ve recently found your blog and am reading through all entries – many are great, keep it up!

    However, this one is hideous, don’t use this :) At least not without assert guards & data range knowledge. We’ve had a bug with this approach back when we used qsort; this obviously fails for sorting integers with large differences (MAXINT > -1, but MAXINT + 1 < 0).

  2. Scott:

    That’s a good point! I updated the post with the caveat.

Leave a comment





Want to paste some code into your comment? Just wrap it in [code] [/code]. Also, please note that off-topic or overly commercial comments will likely be removed at my discretion.