late-binding of name to function pointer and other questions

D

Dennis Chang

Hi all,

I was reading about function pointers and came across something which
intrigued me.
K&R2 calls qsort (pg.119) within main as so:

qsort( (void **) lineptr, 0, nlines-1, (int (*) (void *, void*))(numeric ?
numcmp : strcmp) );

I guess what interests me is the nameless function pointer and then the
binding of a name to it.

I've worked with nameless functions before in other languages but not in C.

So is my reading of this qsort function call correct?

Another question presents itself to me on the following page of K&R2
(pg.120).

/* Declaration qsort */
void qsort( ... )
{
void swap (void *, int, int);
/* ... */
}

It's true you can't declare a function within a function? So that the
forward declaration of swap within qsort doesn't prevent swap from being
called from other functions (since it's defined elsewhere)? So what's the
point of a forward declaration within a function declaration?

Lastly, it is possible to declare a nameless function within a function?
I.e.,
int max20(int a)
{
return { a > 20 ? a : 20 };
}

I mean the {} declares a nameless function, no?


Thanks,
Dennis.
 
A

Artie Gold

Dennis said:
Hi all,

I was reading about function pointers and came across something which
intrigued me.
K&R2 calls qsort (pg.119) within main as so:

qsort( (void **) lineptr, 0, nlines-1, (int (*) (void *, void*))(numeric ?
numcmp : strcmp) );

I guess what interests me is the nameless function pointer and then the
binding of a name to it.

Nope. It's not a `nameless function pointer'. It's a cast.
I've worked with nameless functions before in other languages but not in C.

So is my reading of this qsort function call correct?

See above.
Another question presents itself to me on the following page of K&R2
(pg.120).

/* Declaration qsort */
void qsort( ... )
{
void swap (void *, int, int);
/* ... */
}

It's true you can't declare a function within a function? So that the

Sure you can. But you can't *define* a function within a function.
forward declaration of swap within qsort doesn't prevent swap from being
called from other functions (since it's defined elsewhere)? So what's the
point of a forward declaration within a function declaration?

Lastly, it is possible to declare a nameless function within a function?
I.e.,
int max20(int a)
{
return { a > 20 ? a : 20 };
}

I mean the {} declares a nameless function, no?
No.
In fact, the above is *not* standard C code.

HTH,
--ag
 
R

Russell Hanneken

Dennis said:
I was reading about function pointers and came across something which
intrigued me.
K&R2 calls qsort (pg.119) within main as so:

qsort( (void **) lineptr, 0, nlines-1, (int (*) (void *, void*))(numeric ?
numcmp : strcmp) );

N.B.: The qsort function in their example is not the same as the qsort
function in the C standard library (see page 120 for the qsort function
being used).
I guess what interests me is the nameless function pointer and then the
binding of a name to it.

I've worked with nameless functions before in other languages but not in
C.

So is my reading of this qsort function call correct?

Are you talking about this part:

(int (*) (void *, void*))(numeric ? numcmp : strcmp)

?

I think you're confused about what's going on. First, this expression is
evaluated:

numeric ? numcmp : strcmp

The result of the expression is the address of either numcmp or strcmp,
depending on the value of numeric at run time.

There's a problem here. The type of numcmp's address is:
pointer-to-function-taking-two-char-pointers-and-returning-an-int. The type
of strcmp's address is:
pointer-to-function-taking-two-const-char-pointers-and-returning-an-int
(notice the const). The two operands should be the same type, or at least
the compiler should be able to convert one type to the other automatically.

On page 208 of K&R, the authors write (about the second and third operands
of conditional expressions), "In the type comparison for pointers, any type
qualifiers [like const] in the type to which the pointer points are
insignificant, but the result type inherits qualifiers from both arms of the
conditional."

So it should be okay, but one of the compilers I've tested this code on
gives me an error, and another gives me a warning.

Anyway, let's assume the result of the conditional expression is an address
of type: pointer-to-function taking-two-char-pointers-and-returning-an-int.
What qsort requires for its third parameter is a
pointer-to-function-taking-two-void-pointers-and-returning-an-int. The
conversion between those two types won't happen automatically. So this cast
is added:

(int (*) (void *, void *))

This converts the address to the needed type.

That cast strikes me as suspicious. I'm not sure it's portable.

The authors themselves seem dissatisfied with their example. See their
errata web page:

http://www.cs.bell-labs.com/cm/cs/cbook/2ediffs.html
Another question presents itself to me on the following page of K&R2
(pg.120).

/* Declaration qsort */
void qsort( ... )
{
void swap (void *, int, int);
/* ... */
}

It's true you can't declare a function within a function?

You can declare a function within a function (as above), but you can't
define a function within a function.
So that the
forward declaration of swap within qsort doesn't prevent swap from being
called from other functions (since it's defined elsewhere)?

Well, the declaration is in scope only within qsort. If you need the
declaration to be visible outside qsort, you have to either type the
declaration again, or move the declaration to some other scope.
So what's the point of a forward declaration within a function
declaration?

There's no law against it. I can't think of an advantage to doing it that
way. Some people like the style, I guess.
Lastly, it is possible to declare a nameless function within a function?
I.e.,
int max20(int a)
{
return { a > 20 ? a : 20 };
}

I mean the {} declares a nameless function, no?

Well, no. That's a syntax error. There's no such thing as a nameless
function in C.
 
D

Dennis Chang

Russell Hanneken said:
Dennis said:
I was reading about function pointers and came across something which
intrigued me.
K&R2 calls qsort (pg.119) within main as so:

qsort( (void **) lineptr, 0, nlines-1, (int (*) (void *, void*))(numeric ?
numcmp : strcmp) );

N.B.: The qsort function in their example is not the same as the qsort
function in the C standard library (see page 120 for the qsort function
being used).
I guess what interests me is the nameless function pointer and then the
binding of a name to it.

I've worked with nameless functions before in other languages but not in
C.

So is my reading of this qsort function call correct?

Are you talking about this part:

(int (*) (void *, void*))(numeric ? numcmp : strcmp)

?

I think you're confused about what's going on. First, this expression is
evaluated:

numeric ? numcmp : strcmp

The result of the expression is the address of either numcmp or strcmp,
depending on the value of numeric at run time.

There's a problem here. The type of numcmp's address is:
pointer-to-function-taking-two-char-pointers-and-returning-an-int. The type
of strcmp's address is:
pointer-to-function-taking-two-const-char-pointers-and-returning-an-int
(notice the const). The two operands should be the same type, or at least
the compiler should be able to convert one type to the other automatically.

On page 208 of K&R, the authors write (about the second and third operands
of conditional expressions), "In the type comparison for pointers, any type
qualifiers [like const] in the type to which the pointer points are
insignificant, but the result type inherits qualifiers from both arms of the
conditional."

So it should be okay, but one of the compilers I've tested this code on
gives me an error, and another gives me a warning.

Anyway, let's assume the result of the conditional expression is an address
of type: pointer-to-function taking-two-char-pointers-and-returning-an-int.
What qsort requires for its third parameter is a
pointer-to-function-taking-two-void-pointers-and-returning-an-int. The
conversion between those two types won't happen automatically. So this cast
is added:

(int (*) (void *, void *))

This converts the address to the needed type.

That cast strikes me as suspicious. I'm not sure it's portable.

The authors themselves seem dissatisfied with their example. See their
errata web page:

http://www.cs.bell-labs.com/cm/cs/cbook/2ediffs.html
Another question presents itself to me on the following page of K&R2
(pg.120).

/* Declaration qsort */
void qsort( ... )
{
void swap (void *, int, int);
/* ... */
}

It's true you can't declare a function within a function?

You can declare a function within a function (as above), but you can't
define a function within a function.
So that the
forward declaration of swap within qsort doesn't prevent swap from being
called from other functions (since it's defined elsewhere)?

Well, the declaration is in scope only within qsort. If you need the
declaration to be visible outside qsort, you have to either type the
declaration again, or move the declaration to some other scope.
So what's the point of a forward declaration within a function
declaration?

There's no law against it. I can't think of an advantage to doing it that
way. Some people like the style, I guess.
Lastly, it is possible to declare a nameless function within a function?
I.e.,
int max20(int a)
{
return { a > 20 ? a : 20 };
}

I mean the {} declares a nameless function, no?

Well, no. That's a syntax error. There's no such thing as a nameless
function in C.

Thanks for both your responses. It's clear now. :O)
Dennis.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top