1

I have a function being passed to another function but I'm not sure why both of these work and don't produce any warnings.

typedef short (*COMP)(char  *, char *);

DATA *bst_get(BST *, char *, COMP);

short cmp(char *a, char *b)
{
    if (strstr(a, b))
        return 0;
    return strcmp(a, b);
}

// Both of these produce the same results
//     the difference is '&cmp' vs 'cmp'
data = bst_get(bst, "textA", &cmp);
data = bst_get(bst, "textA", cmp);

So which is the correct usage? Does it matter?

user740521
  • 1,175
  • 4
  • 12
  • 25

2 Answers2

1

In C, functions are converted to pointer to the function when used in expressions.
cmp and &cmp both here represents the address of function, therefore both are equivalent as a function argument to bst_get.

haccks
  • 104,019
  • 25
  • 176
  • 264
1

cmp is an expression with "function type". Expressions with these types are (almost) always implicitly converted to an expression with the corresponding function pointer type, similar (*see note at end) to how expressions with array type are implicitly converted to pointers to the first array element. This implicit conversion is often called decaying, though this is not a term used by the C language standard (but by C++).

&cmp on the other hand makes the conversion explicit: Here you're taking the address of a function, thus receiving a function pointer.

So, bottom line: They're equivalent, and at least in C there's no practical difference between using one over the other.

The relevant part in the standard:

A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".

[N1570 §6.3.2.1/4]

Note: That means, being "explicit" all the times would mean writing function calls like this:

#include <stdio.h>

void foo(void) {
  printf("Awesome\n");
}

int main() {
  (&foo)();
  return 0;
}

*) Important: The similarity mentioned is that there's an implicit conversion happening. While func and &func yield the exact same result (value and type), array and &array yield different results (different pointer types). The reason is that array is implicitly converted to &(array[0]). So, repeat, the similarity is that there are implicit conversions happening. The actual conversions are different.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • 1
    Using just the name of a function is exactly as explicit as using the `&` operator. A function call requires an _explicit_ parenthesis postfix operator. – too honest for this site Mar 02 '16 at 18:21
  • @Olaf I don't really understand what you're trying to tell me. What I'm about is that `cmp` is an expression with function type, that (almost always) is (implicitly) converted to an expression with pointer to function type, as is done explicitly when using operator `&`. – Daniel Jour Mar 02 '16 at 18:30
  • " that (almost always) is" - when is it not? It is not like arrays. It is **only** called as a function if an **explicit** `(` follows. – too honest for this site Mar 02 '16 at 20:08
  • Btw. `sizeof` and `_Alignof` are illegal for functions. – too honest for this site Mar 02 '16 at 20:16
  • @Olaf The implicit conversion isn't happening when using the address of operator (which is then doing an explicit conversion), as be seen in the quote from the standard. That's why I put these parentheses, in all practical cases the conversion happens. Even in the case when calling a function: Actually, we're always calling (through) function pointers. The "like arrays" part is there because the conversion is similar, thus hopefully showing parallels to the reader. – Daniel Jour Mar 02 '16 at 22:13
  • No, they are **not** similar. `&func` yields **exactly** the same as `func` for a function. `&array` does not! And - as I wrote `sizeof(func)` and `_alingof(func)` are illegal, so only `&` is left. And - as I clarified - yields **exactly** the same as `func`. Actually, your statement "Actually, we're always calling (through) function pointers" is correct. So according to your logic, the "correct way was to call a function through `(&func)(...)` and use `funcPtr(...)` only for function pointers, – too honest for this site Mar 02 '16 at 22:15
  • @Olaf Ah, is that what it's been about? What I mean with "similar" is that when using the expression `array` an implicit conversion (to a pointer to its first element) is done. The similarity is the implicit conversion, not that the resulting types of the plain expression and the expression prefixed with the address of operator would yield the same result (which, as you said, it doesn't for arrays, `&array` is a pointer to an array, not to its first element) – Daniel Jour Mar 02 '16 at 22:19
  • Remember this is read by beginners who take such laxness serious. There is already enough confusion about arrays and pointers. So we should be very precise about the terminology. – too honest for this site Mar 02 '16 at 22:21
  • I'll try to make it more precise. – Daniel Jour Mar 02 '16 at 22:22