3

I found the following code from bstrlib, in bstrlib.c (e.g. line 193) :

bstring bfromcstr (const char * str) {
    bstring b;
    int i;
    size_t j;

    if (str == NULL) return NULL;
    j = (strlen) (str);
    i = snapUpSize ((int) (j + (2 - (j != 0))));
    if (i <= (int) j) return NULL;

    b = (bstring) bstr__alloc (sizeof (struct tagbstring));
    if (NULL == b) return NULL;
    b->slen = (int) j;
    if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
        bstr__free (b);
        return NULL;
    }

    bstr__memcpy (b->data, str, j+1);
    return b;
}

What does the line (strlen) (str) mean? This kind of code using strlen is quite common in the bstrlib.c.

I did some test code on a OSX machine, but I can't either understand nor explain what it means.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
teoking
  • 127
  • 7

2 Answers2

11

j = (strlen) (str); is essentially the same as j = strlen(str);.

Writing the code the way they did will ensure that the real strlen function (from <string.h>) will be used, even if it is hidden by a function-like macro named strlen().

A function-like macro is only expanded if its name appears with a pair of parentheses after it. If you write just the name, it is left alone. This can be useful when you have a function and a macro of the same name, and you wish to use the function sometimes.

Because in (strlen) (str), strlen isn't followed by a pair of parenthesis, the macro won't be expanded.

This example should demonstrate:

#include <stdio.h>
#include <string.h>

/**
 * Only check something like this in if you're
 * planning on changing jobs very soon!
 */
#define strlen(s)   666

int main(void)
{
    const char *str = "Stack Overflow";
    size_t j;

    /* This always uses the *real* strlen */
    j = (strlen) (str);
    fprintf(stderr, "(strlen) (str) = %zu\n", j);

    /* This might be using a function-like macro */
    j = strlen(str);
    fprintf(stderr, "strlen(str) = %zu\n", j);

    return 0;
}

Output:

$ ./a.out 
(strlen) (str) = 14
strlen(str) = 666

Of course, the following would have worked as well:

#include ...
...

#ifdef strlen
#undef strlen
#endif
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
4

Functions can be used as pointer to itself just like arrays when used in expression. Therefore strlen(str) is equivalent to (strlen)(str), (*strlen)(str) and (******strlen)(str).

haccks
  • 104,019
  • 25
  • 176
  • 264
  • @dfeuer; I never said pointer to a function is *pointer to pointer*. – haccks Mar 16 '15 at 03:19
  • OK, so how can `(******strlen)(str)` work exactly? I see that it *does*, but I don't understand it. – dfeuer Mar 16 '15 at 03:20
  • 3
    @dfeuer; [Why do all these crazy function pointer definitions all work? What is really going on?](http://stackoverflow.com/a/6893288/2455888). – haccks Mar 16 '15 at 03:26
  • Thanks. It seems C is just completely crazy in that particular corner. – dfeuer Mar 18 '15 at 03:22