views:

364

answers:

2

Today I was writing some C code to sort an array of structs using quicksort with a custom comparator function to determine their ordering.

At first I wrote it with the call to the comparator function hard-coded into the quicksort function. Then I thought perhaps it would be nicer to pass that function as an argument to a generic quicksort function.

In my original code, I had declared the comparator function inline. In my new code, I kept the inline declaration, even though that didn't really make much sense to me, given that the function was being passed as a parameter. However, the compiler didn't complain!

My question is: is the inline declaration having any effect here, or is it merely a recommendation to the compiler which is being ignored?

Original code:

typedef struct _CGRect {
    CGPoint origin;
    CGSize size;
} CGRect;

typedef enum _NSComparisonResult {
     NSOrderedAscending = -1,
     NSOrderedSame,
     NSOrderedDescending
} NSComparisonResult;

static inline NSComparisonResult CGRectCompareRowsFirst(CGRect r1, CGRect r2)
{
    if (r1.origin.y < r2.origin.y)
        return NSOrderedAscending;
    else if (r1.origin.y > r2.origin.y)
        return NSOrderedDescending;
    else
    {
        if (r1.origin.x < r2.origin.x)
            return NSOrderedAscending;
        else if (r1.origin.x > r2.origin.x)
            return NSOrderedDescending;
        else
            return NSOrderedSame;
    }
}

static void CGRectQuicksortRowsFirst(CGRect *left, CGRect *right)
{
    if (right > left) {
        CGRect pivot = left[(right-left)/2];
        CGRect *r = right, *l = left;
        do {
            while (CGRectCompareRowsFirst(*l, pivot) == NSOrderedAscending) l++;
            while (CGRectCompareRowsFirst(*r, pivot) == NSOrderedDescending) r--;
            if (l <= r) {
                CGRect t = *l;
                *l++ = *r;
                *r-- = t;
            }
        } while (l <= r);
        CGRectQuicksortRowsFirst(left, r);
        CGRectQuicksortRowsFirst(l, right);
    }
}

static void CGRectSortRowsFirst(CGRect *array, int length)
{
    CGRectQuicksortRowsFirst(array, array+length-1);
}

New code:

static inline NSComparisonResult CGRectCompareRowsFirst(const void *s1, const void *s2)
{
    CGRect r1 = *(CGRect *)s1, r2 = *(CGRect *)s2;

    if (r1.origin.y < r2.origin.y)
        return NSOrderedAscending;
    else if (r1.origin.y > r2.origin.y)
        return NSOrderedDescending;
    else
    {
        if (r1.origin.x < r2.origin.x)
            return NSOrderedAscending;
        else if (r1.origin.x > r2.origin.x)
            return NSOrderedDescending;
        else
            return NSOrderedSame;
    }
}

static void quick(CGRect *left, CGRect *right, NSComparisonResult(*f)(const void *, const void *))
{
    if (right > left) {
        CGRect pivot = left[(right-left)/2];
        CGRect *r = right, *l = left;
        do {
            while (f(&*l, &pivot) == NSOrderedAscending) l++;
            while (f(&*r, &pivot) == NSOrderedDescending) r--;
            if (l <= r) {
                CGRect t = *l;
                *l++ = *r;
                *r-- = t;
            }
        } while (l <= r);
        quick(left, r, f);
        quick(l, right, f);
    }
}

static void CGRectSortRowsFirst(CGRect *array, int length)
{
    quick(array, array+length-1, CGRectCompareRowsFirst);
}
+10  A: 

Inline is just a recommendation to the compiler, and can be ignored. This can happen for several reasons, such as if the function is too complex to be safely inlined. If you pass it as a parameter to a function like above, the compiler will create the non-inlined version whose address will be passed to the function.

It may be possible that the compiler could still inline the function - for instance, during code generation the compiler could utilize the inline function hint replacing the call via a function pointer to just the expanded function; I am not sure if any current compiler would do that.

Inlined and non-inlined versions can and often do co-exist within one compiled program.

Michael
A: 

The 'inline' keyword is simply a compiler flag that tells it to handle it differently in that it will copy the body of the function and replace it with the actual function call. This is a performance boost if you have a small function that gets reused in many locations in your code. It's a neat thing to use with accessors and modifiers. In your case, I think you could leave it as it is. You're not doing anything heavy. The difference will most likely not be noticeable.

Sergey
Have another look at my question. I know what `inline` does -- I was just wondering how meaningful it is to pass an inline function as an argument to another function.
hatfinch