473,387 Members | 1,791 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

pointer_to_function?

mdh
Could someone please help me understand p 119 of K&R?

This is a version of qsort that, depending on a command line optional
argument ( -n) sorts lines numerically vs lexicographically.

I think the relevant lines ( well, the ones I am having a problem
with) are as follows.
# include.....
etc
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *)); /** declaration**/

main......{
.....
if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));
........
}

What I see is that the decalartion of qsort says that qsort is a
function, whose arguments are an array of pointers ( of type void), 2
integers, and a pointer to a function( that recieives 2 ptrs as
arguments of type void) that returns an integer.

I think I understand the relevance of the void ptrs( from what I have
read). However, the call to qsort in main, leaves me perplexed. I have
been looking at this much of the day, been reading FAQs etc, so it's
time to ask for help.

May 1 '07 #1
53 2860
mdh wrote:
Could someone please help me understand p 119 of K&R?

This is a version of qsort that, depending on a command line optional
argument ( -n) sorts lines numerically vs lexicographically.

I think the relevant lines ( well, the ones I am having a problem
with) are as follows.
# include.....
etc
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *)); /** declaration**/

main......{
.....
if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));
........
}
int (*)(void*, void*))(numeric ? numcmp:strcmp)

Is casting the result of (numeric ? numcmp:strcmp) to the required
function pointer type. I assume numcmp uses int* and strcmp uses const
char* for their parameters, hence the need for a cast.
--
Ian Collins.
May 1 '07 #2
mdh
On Apr 30, 5:46 pm, Ian Collins <ian-n...@hotmail.comwrote:
>int (*)(void*, void*))(numeric ? numcmp:strcmp)
Is casting the result of (numeric ? numcmp:strcmp) to the required
function pointer type. I assume numcmp uses int* and strcmp uses const
char* for their parameters, hence the need for a cast.

correct.
Also, numeric, as you probably guessed, is an integer variable.
So, once the conditional expression is resolved, do you end up with
>int (* numcmp) (void*, void*))
or

>int (*strcmp)(void*, void*) ?
This is somewhat puzzling to me...well, one of the things that is
puzzing!!




May 1 '07 #3
mdh wrote:
Could someone please help me understand p 119 of K&R?

This is a version of qsort that, depending on a command line optional
argument ( -n) sorts lines numerically vs lexicographically.

I think the relevant lines ( well, the ones I am having a problem
with) are as follows.
# include.....
etc
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *)); /** declaration**/

main......{
....
if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));
.......
}

What I see is that the decalartion of qsort says that qsort is a
function, whose arguments are an array of pointers ( of type void), 2
integers, and a pointer to a function( that recieives 2 ptrs as
arguments of type void) that returns an integer.

I think I understand the relevance of the void ptrs( from what I have
read). However, the call to qsort in main, leaves me perplexed. I have
been looking at this much of the day, been reading FAQs etc, so it's
time to ask for help.
First, to forestall some possible confusion: The qsort()
function in this exercise is not the same as the function of
that name in the C Standard library. Pay no heed to people
who tell you that strcmp() is probably not the right comparison
function to use with qsort() -- it probably isn't, but they're
thinking of a different qsort() function altogether.

Now to the question: You're apparently confused by the last
argument in the call

qsort (..., (numeric ? numcmp:strcmp));

This is an example of what's often called the "ternary operator"
or the "?:" operator:

condition ? true_result : false_result

This expression first evaluates `condition' (in this case
`numeric'). If the condition is non-zero (i.e., true), the
value of the expression is `true_result' (or in this case,
it is `numcmp', a pointer to the function named numcmp). If
the condition is zero (false), the value is `false_condition',
or in this case `strcmp'. Other computer languages have had
a similar construct, but have spelled it less confusingly:

if numeric then numcmp else strcmp

.... was the way Algol put it. C's passion for brevity gets
rid of the `if' altogether, and spells `then' and `else' as
`?' and ':', respectively.

The upshot is that this call to qsort() passes as its
fourth argument either a pointer to the numcmp() function or
a pointer to the strcmp() function, depending on the value
of the variable `numeric'. The parentheses that surround the
entire fourth argument are unnecessary, and are presumably
present only for emphasis.

I hope this helps.

And remember: When you graduate to using the "real" qsort(),
you should almost certainly *not* use strcmp() as the final
argument. I believe this is discussed in the FAQ.

--
Eric Sosman
es*****@acm-dot-org.invalid
May 1 '07 #4
mdh wrote:
On Apr 30, 5:46 pm, Ian Collins <ian-n...@hotmail.comwrote:
>int (*)(void*, void*))(numeric ? numcmp:strcmp)
>Is casting the result of (numeric ? numcmp:strcmp) to the required
function pointer type. I assume numcmp uses int* and strcmp uses const
char* for their parameters, hence the need for a cast.


correct.
Also, numeric, as you probably guessed, is an integer variable.
So, once the conditional expression is resolved, do you end up with
>int (* numcmp) (void*, void*))

or

>int (*strcmp)(void*, void*) ?

This is somewhat puzzling to me...well, one of the things that is
puzzing!!

You end up with either the *address* of the function numcmp, or the
address of the function strcmp. Neither of these match the prototype of
int (*)(void*, void*), hence the cast.

This is acceptable in this case because all the functions have two
pointer parameters.

--
Ian Collins.
May 1 '07 #5
mdh
On Apr 30, 5:59 pm, Eric Sosman <esos...@acm-dot-org.invalidwrote:

First, to forestall some possible confusion: The qsort()
function in this exercise is not the same as the function of
that name in the C Standard library.
correct
Now to the question: You're apparently confused by the last
argument in the call
correct again.
>
qsort (..., (numeric ? numcmp:strcmp));

This is an example of what's often called the "ternary operator"
or the "?:" operator:

condition ? true_result : false_result

This must be the same what K&R refer to as "conditional expressions
(p51)).

The upshot is that this call to qsort() passes as its
fourth argument either a pointer to the numcmp() function or
a pointer to the strcmp() function, depending on the value
of the variable `numeric'. The parentheses that surround the
entire fourth argument are unnecessary, and are presumably
present only for emphasis.
Eric...thanks...a really dumb question. Once

qsort (..., (numeric ? numcmp:strcmp));

is evaluated, the "true" function becomes associated with the (*) of
the (*)(void*, void*). Is that because the declaration implies that
the fourth argument is a function pointer(that accepts two ptr
arguments)? So the compiler just "knows" this, or is it obvious to you
from the way it is written?
May 1 '07 #6
mdh wrote:
On Apr 30, 5:59 pm, Eric Sosman <esos...@acm-dot-org.invalidwrote:

> First, to forestall some possible confusion: The qsort()
function in this exercise is not the same as the function of
that name in the C Standard library.

correct
> Now to the question: You're apparently confused by the last
argument in the call

correct again.
> qsort (..., (numeric ? numcmp:strcmp));

This is an example of what's often called the "ternary operator"
or the "?:" operator:

condition ? true_result : false_result


This must be the same what K&R refer to as "conditional expressions
(p51)).

> The upshot is that this call to qsort() passes as its
fourth argument either a pointer to the numcmp() function or
a pointer to the strcmp() function, depending on the value
of the variable `numeric'. The parentheses that surround the
entire fourth argument are unnecessary, and are presumably
present only for emphasis.

Eric...thanks...a really dumb question. Once

qsort (..., (numeric ? numcmp:strcmp));

is evaluated, the "true" function becomes associated with the (*) of
the (*)(void*, void*). Is that because the declaration implies that
the fourth argument is a function pointer(that accepts two ptr
arguments)? So the compiler just "knows" this, or is it obvious to you
from the way it is written?

Maybe if you use a typedef it will be clearer

typedef (*SortFn)(void*, void*);

Then the forth parameter expression becomes

(SortFn)(numeric ? numcmp : strcmp)

I often find confusion with function pointer syntax can be removed with
typedefs.

--
Ian Collins.
May 1 '07 #7
mdh <md**@comcast.netwrote:
Could someone please help me understand p 119 of K&R?
This is a version of qsort that, depending on a command line optional
argument ( -n) sorts lines numerically vs lexicographically.
I think the relevant lines ( well, the ones I am having a problem
with) are as follows.
# include.....
etc
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *)); /** declaration**/
main......{
....
if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));
.......
}
What I see is that the decalartion of qsort says that qsort is a
function, whose arguments are an array of pointers ( of type void), 2
integers, and a pointer to a function( that recieives 2 ptrs as
arguments of type void) that returns an integer.
I think I understand the relevance of the void ptrs( from what I have
read). However, the call to qsort in main, leaves me perplexed. I have
been looking at this much of the day, been reading FAQs etc, so it's
time to ask for help.
Actually the line on p. 119 is

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

without any 'if (' in front of it - which wouldn't work since qsort()
does return void and, moreover, you would end up with something that
looks rather strange (or at least completely useless) like

if (...);

If you are just concerned about the

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

bit (the last argument to your qsort call) it looks more daunting
than it really is. The first part

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

is a cast to the type of function pointer qsort() expects as it's
last argument - a pointer to a function that returns an int and
takes two void pointer arguments. You can decode it the following
way: always start with the innermost parentheses. What you find
there is a '*', so it's a cast to some pointer type. And since its
followed by a pair of parentheses its a poitner to a function. To
the left you have the return value (int) and on the right (within
the parentheses) the types of the arguments of the function. So it
stands for "a pointer to a function that returns int and takes two
void pointer arguments". That's exactly the type that qsort() ex-
pects as its fourth argument and the cast avoids compiler warnings
since both the functions numcmp() and strcmp() are declared to take
two char pointers as their arguments instead of two void pointers.

The second part

(numeric ? numcmp:strcmp)

says: if 'numeric' is non-zero use a pointer to the function numcmp(),
otherwise one to strcmp().

If you put it all together you end up with: if 'numeric' is true
(non-zero) then pass a pointer to the function numcmp() (cast to
the type that qsort() expects) to qsort(), but when 'numeric' is
false (0) then pass a pointer to strcmp() to qsort(). So if the
variable 'numeric' is true qsort() will use the function numcmp()
for comparisons (a function for doing a numerical comparison) and
strcmp() (a function for doing string comparisons) otherwise

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
May 1 '07 #8
mdh
On Apr 30, 5:46 pm, Ian Collins <ian-n...@hotmail.comwrote:
Is casting the result of (numeric ? numcmp:strcmp) to the required
function pointer type. I assume numcmp uses int* and strcmp uses const
char* for their parameters, hence the need for a cast.
Actually Ian, both numcmp and strcmp have 2 arguments of type char *s.
It is just their definitions that are different. Does this effect what
you said about the cast?
May 1 '07 #9
mdh wrote:
On Apr 30, 5:46 pm, Ian Collins <ian-n...@hotmail.comwrote:
>Is casting the result of (numeric ? numcmp:strcmp) to the required
function pointer type. I assume numcmp uses int* and strcmp uses const
char* for their parameters, hence the need for a cast.

Actually Ian, both numcmp and strcmp have 2 arguments of type char *s.
It is just their definitions that are different. Does this effect what
you said about the cast?

No.

--
Ian Collins.
May 1 '07 #10
mdh wrote:
On Apr 30, 5:59 pm, Eric Sosman <esos...@acm-dot-org.invalidwrote:

> First, to forestall some possible confusion: The qsort()
function in this exercise is not the same as the function of
that name in the C Standard library.

correct
> Now to the question: You're apparently confused by the last
argument in the call

correct again.
> qsort (..., (numeric ? numcmp:strcmp));

This is an example of what's often called the "ternary operator"
or the "?:" operator:

condition ? true_result : false_result


This must be the same what K&R refer to as "conditional expressions
(p51)).

> The upshot is that this call to qsort() passes as its
fourth argument either a pointer to the numcmp() function or
a pointer to the strcmp() function, depending on the value
of the variable `numeric'. The parentheses that surround the
entire fourth argument are unnecessary, and are presumably
present only for emphasis.

Eric...thanks...a really dumb question. Once

qsort (..., (numeric ? numcmp:strcmp));

is evaluated, the "true" function becomes associated with the (*) of
the (*)(void*, void*). Is that because the declaration implies that
the fourth argument is a function pointer(that accepts two ptr
arguments)? So the compiler just "knows" this, or is it obvious to you
from the way it is written?
You quoted the qsort() declaration as (slightly reformatted)
void qsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *)); /** declaration**/
This declaration says (among other things) that the fourth
parameter is a pointer to a function that takes two `void*'
arguments and returns an `int' result. That's how the
compiler "knows" this: it's been told.

The call must supply arguments that match (or can be
converted to) the types of the parameters as stated in the
declaration. The declaration says that the function expects
to receive a mocha latte, and when you call it you must
supply a mocha latte or at least a cup of ordinary Joe ("Put
a little cocoa powder and some non-dairy creamer in it; he'll
never spot the difference").

And here's where I may have done you a disservice, reading
a little hastily (I've been doing that a lot lately ...) and
focusing on what you probably understood while ignoring what
now seems to have been the crux of your question. The bare
expression

numeric ? numcmp : strcmp

is probably not of the correct type: You didn't show these
functions (and since qsort() isn't the library's qsort(), it
may well be that strcmp() is idiosyncratic, too), so I can't
tell for sure what parameters they expect and what values
they return. Presumably, they don't match the two-void*-and-
return-an-int that the qsort() declaration advertises. So
the authors coerce the result of the expression by casting it:

(int (*)(void*,void*)) (...the expression ...)

to keep the compiler happy.

Unfortunately, this is a dubious practice. First, if the
types of numcmp() and strcmp() differ, it doesn't work. Why?
Because if numcmp and strcmp are of different types, then what
is the type of the full three-part expression before casting?
The rule is that the second and third operands must be the same
type, or at least must be convertible to the same type. If
they aren't, each operand needs to be converted individually:

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

Even then you're on shaky ground. A rule about function
pointers is that when you use a pointer to call a function, the
type of the pointer must agree with the type of the function
being called: It must agree in the number and type of arguments,
and in the type of the returned value. Now, all this casting
is presumably going on because numcmp and strcmp *don't* take
`void*' parameters and return `int' values. For example, the
Standard strcmp() takes two `const char*' parameters, not two
`void*' parameters. (I don't know what numcmp() takes.) So
when qsort() uses an `int(*)(void*,void*)' function pointer to
call an `int(*)(const char*,const char*)' function, there's no
telling what will happen.

... well, "no telling" overstates the case. On most systems
you'll find that `void*' and `const char*' arguments are treated
identically for purposes of calling functions, so you'll get
away with this little white lie. You are in a state of sin, but
Satan will probably just glower at you a little and not actually
hurl you into the pit of flame. Probably. The risk is yours to
assess, and to accept or decline.

--
Eric Sosman
es*****@acm-dot-org.invalid
May 1 '07 #11
mdh
On Apr 30, 6:30 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
>
Actually the line on p. 119 is

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

without any 'if (' in front of it - which wouldn't .......
of course..thanks.
>
If you are just concerned about the

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

bit (the last argument to your qsort call) it looks more daunting
than it really is.
good.
The first part
>
(int (*)(void*, void*))

is a cast to the type of function pointer qsort() expects as it's
last argument - a pointer to a function that returns an int and
takes two void pointer arguments.
It's a cast because it just says (*)?

You can decode it the following
way: always start with the innermost parentheses. What you find
there is a '*', so it's a cast to some pointer type.


And since its
followed by a pair of parentheses its a poitner to a function. To
the left you have the return value (int) and on the right (within
the parentheses) the types of the arguments of the function. So it
stands for "a pointer to a function that returns int and takes two
void pointer arguments". That's exactly the type that qsort() ex-
pects as its fourth argument and the cast avoids compiler warnings
since both the functions numcmp() and strcmp() are declared to take
two char pointers as their arguments instead of two void pointers.

ok...let me make really sure I understand this. So, if strcmp
( declaration int strcmp( char *, char *) is passed to "this" qsort,
( as it's 4th argument) the compiler would complain as it is
expecting two void ptrs as it's argument to a function. So, the cast
you are talking about, refers to the arguments of the *fp or am I
missing something?
If you put it all together you end up with: if 'numeric' is true
(non-zero) then pass a pointer to the function numcmp() (cast to
the type that qsort() expects) to qsort(), but when 'numeric' is
false (0) then pass a pointer to strcmp() to qsort().
And, as you explained above, starting with the innermost parenthesis,
as this needs a "function" to point to, it resolves the conditional
expression and associates this with the (*).

May 1 '07 #12
"mdh" <md**@comcast.netwrote in message
news:11**********************@y5g2000hsa.googlegro ups.com...
Could someone please help me understand p 119 of K&R?

This is a version of qsort that, depending on a command line
optional argument ( -n) sorts lines numerically vs lexicographically.

I think the relevant lines ( well, the ones I am having a problem
with) are as follows.

# include.....
etc
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *)); /** declaration**/

main......{
....
if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));
.......
}

What I see is that the decalartion of qsort says that qsort is a
function, whose arguments are an array of pointers ( of type void), 2
integers, and a pointer to a function( that recieives 2 ptrs as
arguments of type void) that returns an integer.
Nit: qsort() is a function, whose arguments are an array of
pointers-to-void, two integers, and a pointer-to-function (that receives two
pointers-to-void as arguments) and returns an integer.
I think I understand the relevance of the void ptrs( from what I
have read). However, the call to qsort in main, leaves me
perplexed. I have been looking at this much of the day, been
reading FAQs etc, so it's time to ask for help.
foo = qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));

is a denser way of writing

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

which is a denser way of writing

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

which is a denser way of writing

typedef int (*mycmp)(void*, void*);
if (numeric)
foo = qsort((void**) lineptr, 0, nlines-1, (mycmp)(numcmp));
else
foo = qsort((void**) lineptr, 0, nlines-1, (mycmp)(strcmp))

That make more sense?

I'd say that K&R shouldn't contain such evil syntax, but you'll see it now
and then in the real world, and there's nothing technically wrong with it,
so you should be prepared.

S

--
Stephen Sprunk "Those people who think they know everything
CCIE #3723 are a great annoyance to those of us who do."
K5SSS --Isaac Asimov
--
Posted via a free Usenet account from http://www.teranews.com

May 1 '07 #13
mdh
On Apr 30, 7:14 pm, "Stephen Sprunk" <step...@sprunk.orgwrote:
>
foo = qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));

is a denser way of writing

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

which is a denser way of writing

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

which is a denser way of writing

typedef int (*mycmp)(void*, void*);
if (numeric)
foo = qsort((void**) lineptr, 0, nlines-1, (mycmp)(numcmp));
else
foo = qsort((void**) lineptr, 0, nlines-1, (mycmp)(strcmp))

That make more sense?
I am sure that in time it will make a lot more sense than now. Thanks
for your input.

May 1 '07 #14
mdh said:
# include.....
etc
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *)); /** declaration**/
"119-121(§5.11): The qsort discussion needs recasting in several ways.
First, qsort is a standard routine in ANSI/ISO C, so the rendition here
should be given a different name, especially because the arguments to
standard qsort are a bit different: the standard accepts a base pointer
and a count, while this example uses a base pointer and two offsets."
- Dennis Ritchie, in <http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html>
I think I understand the relevance of the void ptrs( from what I have
read). However, the call to qsort in main, leaves me perplexed. I have
been looking at this much of the day, been reading FAQs etc, so it's
time to ask for help.
I can't help thinking the author was having a (rare) off-day. There are
better ways to explain function pointers.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
May 1 '07 #15
Eric Sosman wrote:
This expression first evaluates `condition' (in this case
`numeric'). If the condition is non-zero (i.e., true), the
value of the expression is `true_result' (or in this case,
it is `numcmp', a pointer to the function named numcmp). If
the condition is zero (false), the value is `false_condition',
or in this case `strcmp'. Other computer languages have had
a similar construct, but have spelled it less confusingly:

if numeric then numcmp else strcmp

... was the way Algol put it. C's passion for brevity gets
rid of the `if' altogether, and spells `then' and `else' as
`?' and ':', respectively.
Algol 68 (as opposed to 60) requires a closing `fi` and also
allows the terse `(condition | then-part | else-part)` plus
|: for elseifs. '68 preceeds C and so could have been (I don't
say was) an influence. As another example language, Pop11 has
if-then-else-endif (and elseifs, and unless, and elseunless).

My feeling is that it's valuable to have a terse form for
expressions (and valuable to drop the statement/expression
distinction, too).

--
Conditional Hedgehog
"Based on their behaviour so far -- I have no idea" /Sahara/

May 1 '07 #16
mdh <md**@comcast.netwrote:
On Apr 30, 6:30 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
The first part

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

is a cast to the type of function pointer qsort() expects as it's
last argument - a pointer to a function that returns an int and
takes two void pointer arguments.
It's a cast because it just says (*)?
Well, yes because there's no other construct where that could
appear and would be syntactically correct.
And since its
followed by a pair of parentheses its a poitner to a function. To
the left you have the return value (int) and on the right (within
the parentheses) the types of the arguments of the function. So it
stands for "a pointer to a function that returns int and takes two
void pointer arguments". That's exactly the type that qsort() ex-
pects as its fourth argument and the cast avoids compiler warnings
since both the functions numcmp() and strcmp() are declared to take
two char pointers as their arguments instead of two void pointers.
ok...let me make really sure I understand this. So, if strcmp
( declaration int strcmp( char *, char *) is passed to "this" qsort,
( as it's 4th argument) the compiler would complain as it is
expecting two void ptrs as it's argument to a function. So, the cast
you are talking about, refers to the arguments of the *fp or am I
missing something?
The compiler may emit a warning because the type of pointer you
pass to qsort() without the cast wouldn't exactly match the type
of function pointer qsort() is declared to take as its fourth
argument. And, yes, it's about the arguments of the function,
there's nothing else that's different.

If the compiler warns you is up to the compiler and probably the
warning level you use. But I suspect the main reason they (K&R)
put in the cast was pedagogical, showing how function pointers
look like. They also write on the next page "The elaborate cast
of the function argument casts the arguments of the comparison
function. These will generally have no effect on actual repre-
sentations, but assure the compiler that all is well."

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
May 1 '07 #17
mdh wrote:
On Apr 30, 6:30 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
>>
The first part

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

is a cast to the type of function pointer qsort() expects as it's
last argument - a pointer to a function that returns an int and
takes two void pointer arguments.

It's a cast because it just says (*)?
No, it is a cast, because it is a 'type-name' enclosed in parentheses.
In this case, the 'type-name' is the whole int (*)(void*, void*) part
within the outer parentheses.
This type-name should be read as: A pointer ( (*) ) to a function,
taking two void* arguments ( (void*, void*) ) and returning an int.

As you can see, the * in the middle has the normal meaning for declaring
a pointer. The parentheses around it are needed to make it clear that
this is a pointer to a function, and not a function returning a
pointer.
The * does NOT work as a kind of placeholder. C never uses place
holders.
>
You can decode it the following
>way: always start with the innermost parentheses. What you find
there is a '*', so it's a cast to some pointer type.

And since its
>followed by a pair of parentheses its a poitner to a function. To
the left you have the return value (int) and on the right (within
the parentheses) the types of the arguments of the function. So it
stands for "a pointer to a function that returns int and takes two
void pointer arguments". That's exactly the type that qsort() ex-
pects as its fourth argument and the cast avoids compiler warnings
since both the functions numcmp() and strcmp() are declared to take
two char pointers as their arguments instead of two void pointers.


ok...let me make really sure I understand this. So, if strcmp
( declaration int strcmp( char *, char *) is passed to "this" qsort,
( as it's 4th argument) the compiler would complain as it is
expecting two void ptrs as it's argument to a function.
I think you have the idea, but it is more correct to say that (this)
qsort expects as fourth argument a pointer to a function, which accepts
two void* arguments.
If you provide something else, the compiler will complain.
So, the cast
you are talking about, refers to the arguments of the *fp or am I
missing something?
In a way, the cast is about the arguments of the function pointer, but
at the same time it is not.
The cast is telling the compiler: I know that neither numcmp nor strcmp
accept void*'s as argument, but I (the programmer) tell you that it
will work if you call any of these functions through the pointer comp
in qsort (at which point, qsort *will* provide two void* arguments).
>
>If you put it all together you end up with: if 'numeric' is true
(non-zero) then pass a pointer to the function numcmp() (cast to
the type that qsort() expects) to qsort(), but when 'numeric' is
false (0) then pass a pointer to strcmp() to qsort().

And, as you explained above, starting with the innermost parenthesis,
as this needs a "function" to point to, it resolves the conditional
expression and associates this with the (*).
No.
The compiler resolves the conditional expression. As the result does not
match the type expected by the qsort function, it is converted to the
correct type (as indicated by the cast), and the result of the
conversion is associated with the parameter comp.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
May 1 '07 #18
mdh
On May 1, 11:01 am, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:
mdh wrote:
(int (*)(void*, void*))
It's a cast because it just says (*)?

No, it is a cast, because it is a 'type-name' enclosed in parentheses.
In this case, the 'type-name' is the whole int (*)(void*, void*) part
within the outer parentheses.
You can decode it the following
way: .............


Thanks...I think I get it now. It's intially hard to wrap ones head
around a simple type like "int" and realize it is just as valid as a
more complicated one like above.

If you put it all together you end up with: if 'numeric' is true
(non-zero) then pass a pointer to the function numcmp() (cast to
the type that qsort() expects) to qsort(), but when 'numeric' is
false (0) then pass a pointer to strcmp() to qsort().
Would this be the same as initializing the ptr to either numcmp or
strcmp ( casting it as discussed above) and then using this as the
argument to qsort?
>
And, as you explained above, starting with the innermost parenthesis,
as this needs a "function" to point to, it resolves the conditional
expression and associates this with the (*).

No.
The compiler resolves the conditional expression. As the result does not
match the type expected by the qsort function, it is converted to the
correct type (as indicated by the cast), and the result of the
conversion is associated with the parameter comp.
Bart...thank you very much. This is heady stuff!!
>
Bart v Ingen Schenau
May 1 '07 #19
mdh
On Apr 30, 5:27 pm, mdh <m...@comcast.netwrote:

Hopefully, I am not driving everyone nuts!!!

Quick question.

the declaration of lineptr is:

char *lineptr[]; an array of char ptrs.

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

when qsort( not the standard one, but the K&R one) is called, lineptr
is preceeded by (void**).

Now, from all the discussions so far, clearly what is happening ( well
I hope) is that lineptr is cast to an array of void pointers.

Could someone just explain the nomenclature?

( I assume doing this would be wrong ) (Void*)....would cast lineptr
to type "ptr to void", which it is clearly not.
But (void **): Type ptr to ptr of type void?

thanks in advance.

May 2 '07 #20
mdh <md**@comcast.netwrites:
On Apr 30, 5:27 pm, mdh <m...@comcast.netwrote:
Hopefully, I am not driving everyone nuts!!!

Quick question.

the declaration of lineptr is:

char *lineptr[]; an array of char ptrs.
If that's a parameter declaration, it doesn't declare an array; it
declares lineptr as a pointer-to-pointer-to-char. (In a parameter
declaration, and *only* in a parameter declaration, something that
looks like it declares an array really declares a pointer. This is
intended as a hint -- to the reader, not to the compiler -- that the
actual argument should point to the first element of an array.)

This would be a lot easier if I could see the relevant declarations
all in one place, without having to go back to previous articles.
>if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));


when qsort( not the standard one, but the K&R one) is called, lineptr
is preceeded by (void**).

Now, from all the discussions so far, clearly what is happening ( well
I hope) is that lineptr is cast to an array of void pointers.
No, (void**) does not convert to an array; it converts to a
pointer-to-pointer-to-void.
Could someone just explain the nomenclature?

( I assume doing this would be wrong ) (Void*)....would cast lineptr
to type "ptr to void", which it is clearly not.
It's (void*), not (Void*).
But (void **): Type ptr to ptr of type void?
Yes.

Have you read section 6 of the comp.lang.c FAQ <http://www.c-faq.com>?

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
May 2 '07 #21
mdh said:
On Apr 30, 5:27 pm, mdh <m...@comcast.netwrote:

Hopefully, I am not driving everyone nuts!!!

Quick question.

the declaration of lineptr is:

char *lineptr[]; an array of char ptrs.

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


when qsort( not the standard one, but the K&R one) is called, lineptr
is preceeded by (void**).
A sure sign that something is screwed up.

K&R2, p119: char *lineptr[MAXLINES];

So lineptr[0] has type char *, and therefore &lineptr[0] has
type char **.

I am not aware of any guarantee whatsoever that there is a meaningful
conversion between char ** and void **.
Now, from all the discussions so far, clearly what is happening ( well
I hope) is that lineptr is cast to an array of void pointers.
No, it's cast to a pointer to pointer to void.
Could someone just explain the nomenclature?

( I assume doing this would be wrong ) (Void*)....would cast lineptr
to type "ptr to void", which it is clearly not.
But (void **): Type ptr to ptr of type void?
"Pointer to void *"
"Pointer to pointer to void"
"Pointer to void pointer"

Take your pick.

I am becoming a little concerned by this p119.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
May 2 '07 #22
"mdh" <md**@comcast.netwrote in message
news:11**********************@h2g2000hsg.googlegro ups.com...
the declaration of lineptr is:

char *lineptr[]; an array of char ptrs.
>if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));

when qsort( not the standard one, but the K&R one) is called, lineptr
is preceeded by (void**).

Now, from all the discussions so far, clearly what is happening ( well
I hope) is that lineptr is cast to an array of void pointers.
Actually, the opposite. lineptr is an array of pointers to char, but the
function wants a pointer to pointer to void. The types are actually
compatible, but you can't convert between them without a cast.

This is similar to how plain pointers and plain arrays are compatible. The
standard specifically states that an array of T decays to a pointer to T in
most contexts because it's so frequently useful (particularly for
manipulating strings); however, that was not extended to more complex
scenarios that are less common (and thus more likely to be mistakes), so a
cast is necessary.

S

--
Stephen Sprunk "Those people who think they know everything
CCIE #3723 are a great annoyance to those of us who do."
K5SSS --Isaac Asimov
--
Posted via a free Usenet account from http://www.teranews.com

May 2 '07 #23
mdh
On May 1, 10:52 pm, Keith Thompson <k...@mib.orgwrote:
>>
char *lineptr[]; an array of char ptrs.

If that's a parameter declaration, it doesn't declare an array; it
declares lineptr as a pointer-to-pointer-to-char. (In a parameter
declaration, and *only* in a parameter declaration, something that
looks like it declares an array really declares a pointer. This is
intended as a hint -- to the reader, not to the compiler -- that the
actual argument should point to the first element of an array.)

This would be a lot easier if I could see the relevant declarations
all in one place, without having to go back to previous articles.
#include <stdio.h>
#include <string.h>
#define MAXLINES 5
#define MAXLEN 10

char *lineptr[MAXLINES];
int readlines( char *[], int);
void writelines(char *[], int );
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *));
void error(char *s);
int numcmp( char *, char *);
int mystrcmp( char *, char *);
int *alloc( int len);
int main (int argc, const char * argv[]){
.....
}


>
No, (void**) does not convert to an array; it converts to a
pointer-to-pointer-to-void.
point taken.
But (void **): Type ptr to ptr of type void?

Yes.

Have you read section 6 of the comp.lang.c FAQ <http://www.c-faq.com>?
I have certainly tried.

May 2 '07 #24
mdh
On May 1, 11:02 pm, "Stephen Sprunk" <step...@sprunk.orgwrote:
"mdh" <m...@comcast.netwrote in message
the declaration of lineptr is:
char *lineptr[]; an array of char ptrs.
Now, from all the discussions so far, clearly what is happening ( well
I hope) is that lineptr is cast to an array of void pointers.
Actually, the opposite. lineptr is an array of pointers to char, but the
function wants a pointer to pointer to void. The types are actually
compatible, but you can't convert between them without a cast.
Ok...I see what you are saying.
This is similar to how plain pointers and plain arrays are compatible. The
standard specifically states that an array of T decays to a pointer to T in
most contexts because it's so frequently useful (particularly for
manipulating strings); however, that was not extended to more complex
scenarios that are less common (and thus more likely to be mistakes), so a
cast is necessary.
Thank you.

May 2 '07 #25
mdh
On May 1, 10:52 pm, Keith Thompson <k...@mib.orgwrote:
char *lineptr[]; an array of char ptrs.
If that's a parameter declaration, it doesn't declare an array; it
declares lineptr as a pointer-to-pointer-to-char. (In a parameter
declaration, and *only* in a parameter declaration, something that
looks like it declares an array really declares a pointer. This is
intended as a hint -- to the reader, not to the compiler -- that the
actual argument should point to the first element of an array.)
This would be a lot easier if I could see the relevant declarations
all in one place, without having to go back to previous articles.

#include <stdio.h>
#include <string.h>
#define MAXLINES 5
#define MAXLEN 10
char *lineptr[MAXLINES];
int readlines( char *[], int);
void writelines(char *[], int );
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *));
void error(char *s);
int numcmp( char *, char *);
int mystrcmp( char *, char *);
int *alloc( int len);
int main (int argc, const char * argv[]){
.....

if ....... {
qsort((void **) lineptr, 0, nlines-1, (int (*)(void*, void*))
numeric ? numcmp:mystrcmp);
........
return 0;
}
No, (void**) does not convert to an array; it converts to a
pointer-to-pointer-to-void.

point taken.
But (void **): Type ptr to ptr of type void?
Yes.
Have you read section 6 of the comp.lang.c FAQ <http://www.c-faq.com>?

I have certainly tried.

May 2 '07 #26
mdh wrote:
>
Thanks...I think I get it now. It's intially hard to wrap ones head
around a simple type like "int" and realize it is just as valid as a
more complicated one like above.
And C's type declaration syntax does not make it any easier.
Once you need pointers to complicated types (such as pointers to
functions and pointers to arrays), you are well advised to make liberal
use of typedef's, to keep the code readable and understandable.
>
>
If you put it all together you end up with: if 'numeric' is true
(non-zero) then pass a pointer to the function numcmp() (cast to
the type that qsort() expects) to qsort(), but when 'numeric' is
false (0) then pass a pointer to strcmp() to qsort().

Would this be the same as initializing the ptr to either numcmp or
strcmp ( casting it as discussed above) and then using this as the
argument to qsort?
Yes, that would have the same effect, and it would make the call to
qsort more readable as well.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
May 2 '07 #27
mdh wrote:
On May 1, 10:52 pm, Keith Thompson <k...@mib.orgwrote:
.... snip ...
>>
If that's a parameter declaration, it doesn't declare an array; it
declares lineptr as a pointer-to-pointer-to-char. (In a parameter
declaration, and *only* in a parameter declaration, something that
looks like it declares an array really declares a pointer. This is
intended as a hint -- to the reader, not to the compiler -- that
the actual argument should point to the first element of an array.)

This would be a lot easier if I could see the relevant declarations
all in one place, without having to go back to previous articles.

#include <stdio.h>
#include <string.h>
#define MAXLINES 5
#define MAXLEN 10

char *lineptr[MAXLINES];
int readlines( char *[], int);
void writelines(char *[], int );
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *));
void error(char *s);
int numcmp( char *, char *);
int mystrcmp( char *, char *);
int *alloc( int len);
int main (int argc, const char * argv[]){
....
}
At least the qsort declaration is wrong. It should be:

void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));

and alloc smells like malloc, which again is:

void *malloc(size_t lgh);

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>
<http://kadaitcha.cx/vista/dogsbreakfast/index.html>
cbfalconer at maineline dot net

--
Posted via a free Usenet account from http://www.teranews.com

May 2 '07 #28
CBFalconer <cb********@yahoo.comwrote:
mdh wrote:
char *lineptr[MAXLINES];
int readlines( char *[], int);
void writelines(char *[], int );
void qsort(void *lineptr[], int left, int right, int (*comp)(void *,
void *));
void error(char *s);
int numcmp( char *, char *);
int mystrcmp( char *, char *);
int *alloc( int len);
int main (int argc, const char * argv[]){
....
}
At least the qsort declaration is wrong. It should be:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
and alloc smells like malloc, which again is:
void *malloc(size_t lgh);
As pointed out somewhere up-thread it's an example from K&R2
(p. 119) and the qsort() used there is not the one from the
standard library.
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
May 2 '07 #29
On Wed, 2 May 2007 01:02:09 -0500, "Stephen Sprunk"
<st*****@sprunk.orgwrote:
>"mdh" <md**@comcast.netwrote in message
news:11**********************@h2g2000hsg.googlegr oups.com...
>the declaration of lineptr is:

char *lineptr[]; an array of char ptrs.
>>if(qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))
(numeric ? numcmp:strcmp));

when qsort( not the standard one, but the K&R one) is called, lineptr
is preceeded by (void**).

Now, from all the discussions so far, clearly what is happening ( well
I hope) is that lineptr is cast to an array of void pointers.

Actually, the opposite. lineptr is an array of pointers to char, but the
function wants a pointer to pointer to void. The types are actually
compatible, but you can't convert between them without a cast.
If they were compatible, there would be an implicit conversion between
them and the cast would not be necessary. The fact that a cast is
necessary is equivalent to being incompatible.

While the standard guarantees that a void* and a char* have the same
characteristics, such as size, representation, alignment, which also
insures that an array of each has the same characteristics, that need
not hold true for void** and char**.
>
This is similar to how plain pointers and plain arrays are compatible. The
Only for a very limited meaning of compatible.
>standard specifically states that an array of T decays to a pointer to T in
most contexts because it's so frequently useful (particularly for
manipulating strings); however, that was not extended to more complex
scenarios that are less common (and thus more likely to be mistakes), so a
cast is necessary.

Remove del for email
May 3 '07 #30
Bart van Ingen Schenau wrote:
>
mdh wrote:

Thanks...I think I get it now. It's intially hard to wrap ones head
around a simple type like "int" and realize it is just as valid as a
more complicated one like above.

And C's type declaration syntax does not make it any easier.
Once you need pointers to complicated types (such as pointers to
functions and pointers to arrays), you are well advised to make liberal
use of typedef's, to keep the code readable and understandable.
Especially when you start passing pointers to functions a parameters
and return values. Which would you rather see?

void (*signal(int sig, void (*func)(int)))(int);

or

typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);

[...]

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h|
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
May 3 '07 #31
>Bart van Ingen Schenau wrote:
>Once you need pointers to complicated types (such as pointers to
functions and pointers to arrays), you are well advised to make liberal
use of typedef's, to keep the code readable and understandable.
In article <46***************@spamcop.net>
Kenneth Brody <ke******@spamcop.netwrote:
>Especially when you start passing pointers to functions a parameters
and return values. Which would you rather see?

void (*signal(int sig, void (*func)(int)))(int);

or

typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);
Indeed. I think it is also noteworthy that the second form
makes it instantly obvious that signal()'s return value has
the same type as its second argument.

This falls into a more general class of "when to name something".
There are two ways to identify some entity: by description, or
by name:

- "She was five feet seven inches of long legs, tawny skin,
luxurious hair, and breath that could knock out an elephant."

- "Marie."

(apologies to anyone named Marie :-) )

If some entity appears only once, "description" is usually enough.
In code, this may take the form of simply writing out a formula:

result = (-b + sqrt(b*b - 4*a*c)) / (2 * a);

But if this is going to appear repeatedly, give it a name:

/* first root of quadradic equation, ax**2 + bx + c */
#define quadradic_root_1(a, b, c) ...

(or make this a function, but either way it has a name). Names
have a sort of "cognitive cost" -- the reader has to learn an
association from name to underlying entity -- but come with a
corresponding "cognitive benefit". The benefit usually outweighs
the cost within a few repetitions.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
May 3 '07 #32
On May 4, 1:47 am, Kenneth Brody <kenbr...@spamcop.netwrote:
Especially when you start passing pointers to functions a parameters
and return values. Which would you rather see?

void (*signal(int sig, void (*func)(int)))(int);

or

typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);
Neither! I prefer to avoid pointer typedefs; they make code more
obfuscated by not making it immediately apparent that you are
dealing with a pointer.

typedef void (sig_t)(int);
sig_t *signal( int sig, sig_t *func );

May 3 '07 #33
On May 3, 1:12 pm, Chris Torek <nos...@torek.netwrote:
Bart van Ingen Schenau wrote:
Once you need pointers to complicated types (such as pointers to
functions and pointers to arrays), you are well advised to make liberal
use of typedef's, to keep the code readable and understandable.

In article <4639E7E5.C3AA7...@spamcop.net>
Kenneth Brody <kenbr...@spamcop.netwrote:
Especially when you start passing pointers to functions a parameters
and return values. Which would you rather see?
void (*signal(int sig, void (*func)(int)))(int);
or
typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);

Indeed. I think it is also noteworthy that the second form
makes it instantly obvious that signal()'s return value has
the same type as its second argument.

This falls into a more general class of "when to name something".
There are two ways to identify some entity: by description, or
by name:

- "She was five feet seven inches of long legs, tawny skin,
luxurious hair, and breath that could knock out an elephant."

- "Marie."

(apologies to anyone named Marie :-) )

If some entity appears only once, "description" is usually enough.
In code, this may take the form of simply writing out a formula:

result = (-b + sqrt(b*b - 4*a*c)) / (2 * a);

But if this is going to appear repeatedly, give it a name:

/* first root of quadradic equation, ax**2 + bx + c */
#define quadradic_root_1(a, b, c) ...
An aside:

#include <math.h>
#include <stdio.h>
double sign(double x)
{
return x < 0 ? -1.0 : 1.0;
}
/*
Due to Knuth, IIRC.
*/
int quadratic_equation_c(double a, double b, double c,
double *root1, double *root2)
{
double q;
if (a == 0) {
*root1 = 0;
*root2 = 0;
return 0;
}
q = -0.5 * (b + sign(b) * sqrt(b * b - 4 * a * c));
*root1 = q / a;
if (q == 0) {
*root2 = 0;
return 0;
}
*root2 = c / q;
return 1;

}
/*
Numerical problems if a or c (or both) are small in magnitude.
*/
int quadratic_equation_a(double a, double b, double c,
double *root1, double *root2)
{
double bsm4ac;
double sbsm4ac;
bsm4ac = b * b - 4 * a * c;
if (bsm4ac < 0 || a == 0) {
*root1 = 0;
*root2 = 0;
return 0;
}
sbsm4ac = sqrt(bsm4ac);
*root1 = (-b + sbsm4ac) / (a + a);
*root2 = (-b - sbsm4ac) / (a + a);
return 1;
}

/*
Numerical problems if a or c (or both) are small in magnitude.
*/
int quadratic_equation_b(double a, double b, double c,
double *root1, double *root2)
{
double bsm4ac;
double sbsm4ac;
bsm4ac = b * b - 4 * a * c;
if (bsm4ac < 0) {
*root1 = 0;
*root2 = 0;
return 0;
}
sbsm4ac = sqrt(bsm4ac);
if (( -b + sbsm4ac) == 0) {
*root1 = 0;
*root2 = 0;
return 0;
}
*root1 = 2 * c / (-b + sbsm4ac);
*root2 = 2 * c / (-b - sbsm4ac);
return 1;
}

int main(void)
{
double a = 1e-50;
double b = -1.0;
double c = 2.0;
double root1;
double root2;
if (quadratic_equation_c(a, b, c, &root1, &root2)) {
printf("processing equation %g*x^2 + %g*x + %g = 0, roots are
%g, %g\n", a, b, c, root1, root2);
} else {
printf("error processing equation %g*x^2 + %g*x + %g = 0\n",
a, b, c);
}

if (quadratic_equation_b(a, b, c, &root1, &root2)) {
printf("processing equation %g*x^2 + %g*x + %g = 0, roots are
%g, %g\n", a, b, c, root1, root2);
} else {
printf("error processing equation %g*x^2 + %g*x + %g = 0\n",
a, b, c);
}

if (quadratic_equation_a(a, b, c, &root1, &root2)) {
printf("processing equation %g*x^2 + %g*x + %g = 0, roots are
%g, %g\n", a, b, c, root1, root2);
} else {
printf("error processing equation %g*x^2 + %g*x + %g = 0\n",
a, b, c);
}

return 0;
}
/*
processing equation 1e-050*x^2 + -1*x + 2 = 0, roots are 1e+050, 2
processing equation 1e-050*x^2 + -1*x + 2 = 0, roots are 2, 1.#INF
processing equation 1e-050*x^2 + -1*x + 2 = 0, roots are 1e+050, 0
*/

(or make this a function, but either way it has a name). Names
have a sort of "cognitive cost" -- the reader has to learn an
association from name to underlying entity -- but come with a
corresponding "cognitive benefit". The benefit usually outweighs
the cost within a few repetitions.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.

May 3 '07 #34
Chris Torek wrote:
[...]
- "She was five feet seven inches of long legs, tawny skin,
luxurious hair, and breath that could knock out an elephant."
Chris, you've been at the keyboard too long.

--
Eric Sosman
es*****@acm-dot-org.invalid
May 4 '07 #35
mdh
On May 3, 8:06 pm, Eric Sosman <esos...@acm-dot-org.invalidwrote:
May I ask a follow up question?
>From all of the discussions so far, it is apparent ( well, I think it
is) that a value of type "pointer to char" can be cast to "pointer to
void" and back again without using an (explicit) cast, but a value of
type "pointer to pointer to char" needs an explicit cast for pointer
to pointer to void. Does anyone know if ( a)
this is indeed true
and (b) why this is the case?

Thanks.

May 4 '07 #36
mdh said:
On May 3, 8:06 pm, Eric Sosman <esos...@acm-dot-org.invalidwrote:
May I ask a follow up question?
>>From all of the discussions so far, it is apparent ( well, I think it
is) that a value of type "pointer to char" can be cast to "pointer to
void" and back again
Well, it can, but why use a cast? You don't need one:

char *p = "Hello world";
void *q = p;
char *r = q;

if(p == r)
{
puts("Your compiler obeys C's rules.");
}

without using an (explicit) cast,
No. You can't cast without using a cast. But of course you don't need a
cast in the above case.
but a value of
type "pointer to pointer to char" needs an explicit cast for pointer
to pointer to void.
That's a hint that it's a dumb thing to do. I really don't know what bwk
was thinking when he wrote that. Possibly something like "where shall I
go for my holidays this year?"

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
May 4 '07 #37
mdh
On May 4, 9:53 am, Richard Heathfield <r...@see.sig.invalidwrote:
mdh said:

From all of the discussions so far, it is apparent ( well, I think
it
is) that a value of type "pointer to char" can be cast to "pointer to
void" and back again

Well, it can, but why use a cast? You don't need one:

char *p = "Hello world";
void *q = p;
char *r = q;

if(p == r)
I think I am using the word cast incorrectly then. What do you call
the the line

void *q=p;?

I thought that cast implied a change of type?

but a value of
type "pointer to pointer to char" needs an explicit cast for pointer
to pointer to void.

That's a hint that it's a dumb thing to do.

Richard, are you saying it is a silly thing to do in general, or
specifically in this case?

I really don't know what bwk
was thinking when he wrote that. Possibly something like "where shall I
go for my holidays this year?"
Perhaps he was just using it as a (poor) example of how to perform an
explicit cast. Moreover, in the "errata" section of the book, he
ruminates that p119 may have contained code not up to his usual
standard and that ..... "There are too many lessons in these pages"
May 4 '07 #38
mdh wrote, On 04/05/07 18:36:
On May 4, 9:53 am, Richard Heathfield <r...@see.sig.invalidwrote:
>mdh said:
>>From all of the discussions so far, it is apparent ( well, I think
it
>>is) that a value of type "pointer to char" can be cast to "pointer to
void" and back again
Well, it can, but why use a cast? You don't need one:

char *p = "Hello world";
void *q = p;
char *r = q;

if(p == r)

I think I am using the word cast incorrectly then. What do you call
the the line

void *q=p;?

I thought that cast implied a change of type?
You were wrong. Where is the change of type in the following:
int i=1;
int j=(int)i;

There are even occasions where it can make some sense to do a cast that
does not actually change the type, however they are rare so you should
not worry about them for now.

In something like:
int i;
void *p = &i;
The conversion from "pointer to int" to "pointer to void" is called a
conversion.
>>but a value of
type "pointer to pointer to char" needs an explicit cast for pointer
to pointer to void.
That's a hint that it's a dumb thing to do.

Richard, are you saying it is a silly thing to do in general, or
specifically in this case?
Whenever you do not fully understand why you need a cast and why it is
valid in that particular situation putting in a cast is a dumb thing to
do. This was merely one instance.

Note that putting in a cast where it is needed and correct *and* you
understand why this is the case, is a sensible cast.

For why void** is not a generic pointer to pointer, see question 4.9 of
the comp.lang.c FAQ at http://c-faq.com/

In fact, as you are still learning about pointer (and probably related
matters) you would probably find reading all of sections 4, 5, 6, 7 and
8 useful. The rest of the FAQ is worth looking at over time as well.
I really don't know what bwk
>was thinking when he wrote that. Possibly something like "where shall I
go for my holidays this year?"

Perhaps he was just using it as a (poor) example of how to perform an
explicit cast. Moreover, in the "errata" section of the book, he
ruminates that p119 may have contained code not up to his usual
standard and that ..... "There are too many lessons in these pages"
No book is perfect.
--
Flash Gordon
May 4 '07 #39
mdh said:
On May 4, 9:53 am, Richard Heathfield <r...@see.sig.invalidwrote:
>mdh said:
>
>>From all of the discussions so far, it is apparent ( well, I think
it
is) that a value of type "pointer to char" can be cast to "pointer
to void" and back again

Well, it can, but why use a cast? You don't need one:

char *p = "Hello world";
void *q = p;
char *r = q;

if(p == r)

I think I am using the word cast incorrectly then.
It would appear so.
What do you call the the line

void *q=p;?
It's an assignment statement involving a conversion from char * to
void *.
I thought that cast implied a change of type?
No, a cast is an *explicit* conversion of a value from one type to
another, like this: (type)value

e.g. (int)3.141
but a value of
type "pointer to pointer to char" needs an explicit cast for
pointer to pointer to void.

That's a hint that it's a dumb thing to do.


Richard, are you saying it is a silly thing to do in general, or
specifically in this case?
It is almost always a mistake to use a cast, and the places where it's
right are not the places most people appear to expect. If you find
yourself using a cast (except in some rather specialised
circumstances), you're probably coding around a design flaw in your
program, and the proper corrective action is to re-design the program.
I really don't know what bwk
>was thinking when he wrote that. Possibly something like "where shall
I go for my holidays this year?"

Perhaps he was just using it as a (poor) example of how to perform an
explicit cast.
Well, the redundant expression "explicit cast" is redundant, as it says
the same thing twice, redundantly repeating itself. A cast is an
explicit conversion.
Moreover, in the "errata" section of the book, he
ruminates that p119 may have contained code not up to his usual
standard and that ..... "There are too many lessons in these pages"
See also Ecclesiastes 12:12.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
May 4 '07 #40
Richard Heathfield said:
mdh said:
>What do you call the the line

void *q=p;?

It's an assignment statement involving a conversion from char * to
void *.
No it isn't. It's a definition and initialisation involving a conversion
from char * to void *.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
May 4 '07 #41
mdh
On May 4, 9:53 am, mdh wrote;
I thought that cast implied a change of type?
On May 4, 11:38 am, Flash Gordon <s...@flash-gordon.me.ukwrote:
>
You were wrong.
>From FAQ 2.7.
"Casts can be a bit confusing at first. A cast is the syntax used to
request an explicit type conversion; coercion is just a more formal
word for ``conversion.'' A cast consists of a type name in parentheses
and is used as a unary operator."

Where is the change of type in the following:
int i=1;
int j=(int)i;
Now, you are clearly an expert, so I am in no way wanting to sound
smart. But you can see how the FAQs can sometimes lead to confusion,
and asking a question of the combined knowledge of all of the clc
often gives me insight that I have not had before.

The conversion from "pointer to int" to "pointer to void" is called a
conversion.
Presuambly because it is done automatically by the compiler?
Whenever you do not fully understand why you need a cast and why it is
valid in that particular situation putting in a cast is a dumb thing to
do. This was merely one instance.

Again...and if you look at my posts...I really never try and give a
wise-ass reply. But, often, asking about something that might seem
very obscure, leads to enlightenment in other areas that were pretty
murky as well...Well, that's the way I work, anyway.

>
For why void** is not a generic pointer to pointer, see question 4.9 of
the comp.lang.c FAQ athttp://c-faq.com/
Boy...now that is truly WAY beyond me.

:-)
No book is perfect.

Well, I have found it to be , with all the clc input, a wonderful
resource.

Thanks for your help


May 4 '07 #42
mdh wrote:
>
May I ask a follow up question?

From all of the discussions so far, it is apparent ( well, I think
it is) that a value of type "pointer to char" can be cast to
"pointer to void" and back again without using an (explicit) cast,
but a value of type "pointer to pointer to char" needs an explicit
cast for pointer to pointer to void. Does anyone know if (a) this
is indeed true and (b) why this is the case?
What has this got to do with Marie :-)

At any rate, at least in part, this is because the standard
specifies that a pointer to char will have the same representation
as a pointer to void. The other casts you specify are probably
errors, since the two pointer types may require different content.
I.E. they may not work on some C implementation.

In general, casts are probably errors of some form. The major
exception is arguments for printf, and similar.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>
<http://kadaitcha.cx/vista/dogsbreakfast/index.html>
cbfalconer at maineline dot net

--
Posted via a free Usenet account from http://www.teranews.com

May 4 '07 #43
mdh
On May 4, 12:32 pm, CBFalconer <cbfalco...@yahoo.comwrote:
mdh wrote:
>
>
What has this got to do with Marie :-)
As far as I am aware, Marie underwent one of the most important
"conversions" in history. From all the sources I have consulted, I am
not sure if this was a "conversion" or an explicit "cast".
Irrespective, it just shows how historically important those changes
can be!!! :-)

At any rate, at least in part, this is because the standard
specifies that a pointer to char will have the same representation
as a pointer to void. The other casts you specify are probably
errors, since the two pointer types may require different content.
I.E. they may not work on some C implementation.

In general, casts are probably errors of some form.
yes..I certainly see the general dislike for them on the clc. I think
I am going to remove p119 from K&R!!!

Thanks for your imput.

May 4 '07 #44
mdh <md**@comcast.netwrites:
[...]
On May 4, 11:38 am, Flash Gordon <s...@flash-gordon.me.ukwrote:
[...]
>The conversion from "pointer to int" to "pointer to void" is called a
conversion.

Presuambly because it is done automatically by the compiler?
[...]

No, it's called a conversion because it's a conversion.

A *conversion* is an operation that takes a value of some type and
yields a corresponding value of the specified type. This operation
happens during execution, usually as part of the evaluation of an
expression.

A conversion can be either implicit or explicit. For example:

int i = 42;
double d;

d = i;

The value of i is *implicitly* converted from type int to type double,
yielding the value 42.0.

int i = 42;
double d;

d = (double)i;

A cast operator is used to *explicitly* convert the value of i from
type int to type double. (Note that the cast is unnecesary, since the
value would have been converted implicitly anyway. There are cases,
such as pointer conversions, where a conversion can only be performed
explicitly, i.e., via a cast.)

These both do exactly the same thing; the same conversion is performed
in both cases.

The term "cast" is sometimes incorrectly used to refer to conversions
in general. In fact, the term "cast" refers *only* to the use of a
cast operator. Thus there's no such thing as an "implicit cast", and
the term "explicit cast" is redundant.

So what if a cast specifies the same type as its operand?

int i = 42;
int j;
j = (int)i;

There are two possible ways to look at this. Either the cast
specifies a trivial conversion from type int to type int, or it
doesn't specify a conversion at all. It doesn't really make any
difference which way you choose to describe this odd corner case. The
standard happens to say that it doesn't specify a conversion. C99
6.5.4p4:

Preceding an expression by a parenthesized type name converts the
value of the expression to the named type. This construction is
called a *cast*. A cast that specifies no conversion has no
effect on the type or value of an expression.

Strictly speaking, I think there's a contradiction between the first
and last sentences of that paragraph, but it's not a huge deal. I
didn't even remember which way the standard describes this until I
looked it up.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
May 4 '07 #45
mdh
On May 4, 1:37 pm, Keith Thompson <k...@mib.orgwrote:

A *conversion* is an operation that takes a value of some type and
yields a corresponding value of the specified type. This operation
happens during execution, usually as part of the evaluation of an
expression.

A conversion can be either implicit or explicit. For example:
The value of i is *implicitly* converted from type int to type double,

.........
A cast operator is used to *explicitly* convert the value of i from
type int to type double.
These both do exactly the same thing; the same conversion is performed
in both cases.

The term "cast" is sometimes incorrectly used to refer to conversions
in general. In fact, the term "cast" refers *only* to the use of a
cast operator. Thus there's no such thing as an "implicit cast", and
the term "explicit cast" is redundant.

Keith...thanks so much. That's really clear... c is truly a
"language" of words. And misusing/abusing them, is fraught with
danger.

thanks again.

May 4 '07 #46
"mdh" <md**@comcast.netwrote in message
news:11**********************@e65g2000hsc.googlegr oups.com...
I think I am using the word cast incorrectly then. What do you call
the the line

void *q=p;?

I thought that cast implied a change of type?
No, you're thinking of a "conversion". Some conversions are implicit,
meaning a cast is _not_ used; other conversions are explicit, meaning a cast
_is_ used.

If your compiler doesn't warn you about an implicit conversion, odds are
it's legal and meaningful*. If your compiler does warn you, odds are it's
not. You should only use a cast (therefore making an explicit conversion)
when you're absolutely sure you know the warning is wrong -- and it usually
isn't. Unnecessary casts hide bugs.

(* assuming you're using a decent, modern compiler with all the appropriate
warnings enabled. For GCC, this means "-ansi -pedantic -W -Wall".)

S

--
Stephen Sprunk "Those people who think they know everything
CCIE #3723 are a great annoyance to those of us who do."
K5SSS --Isaac Asimov
--
Posted via a free Usenet account from http://www.teranews.com

May 4 '07 #47
On 4 May 2007 10:36:01 -0700, in comp.lang.c , mdh <md**@comcast.net>
wrote:
>
I think I am using the word cast incorrectly then. What do you call
the the line

void *q=p;?
Thats a conversion (assuming p is of type pointer-to-something).
>I thought that cast implied a change of type?
a cast is an explicit conversion, wher you have to *tell* the compiler
what type you want, because it may not figure it out by itself:

int *j=4;
double x = (double)j;
>That's a hint that it's a dumb thing to do.

Richard, are you saying it is a silly thing to do in general, or
specifically in this case?
He's saying that if you have to insert a cast, it often means you're
doing something that is illegal, unsupported or nonportable. Look
again at the above fragment to see what I mean.

The rule with casts in C: use them only when you know *why* you need
them. Never use them just to silence a compiler warning.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
May 4 '07 #48
mdh wrote, On 04/05/07 20:24:
>>On May 4, 9:53 am, mdh wrote;
>>I thought that cast implied a change of type?

On May 4, 11:38 am, Flash Gordon <s...@flash-gordon.me.ukwrote:
<snip>
Now, you are clearly an expert, so I am in no way wanting to sound
smart. But you can see how the FAQs can sometimes lead to confusion,
<snip>
Again...and if you look at my posts...I really never try and give a
wise-ass reply. But, often, asking about something that might seem
very obscure, leads to enlightenment in other areas that were pretty
murky as well...Well, that's the way I work, anyway.
Just to be clear, I had no objection to your getting it wrong nor to
asking about it. Making mistakes which are corrected and asking
questions are important parts of learning.
>For why void** is not a generic pointer to pointer, see question 4.9 of
the comp.lang.c FAQ athttp://c-faq.com/

Boy...now that is truly WAY beyond me.

:-)
That section is relevant, and working on understanding it will help you
understand a lot about pointers.

Keep referring to the FAQ as you learn and it will slowly make more
sense. Also ask questions about the you have problems with, there will
always be someone happy to expand on what the FAQ says.
>>No book is perfect.

Well, I have found it to be , with all the clc input, a wonderful
resource.
K&R2 is an *excellent* book. Many (including me) continue to refer to it
years after having started learning C.
Thanks for your help
Always nice to be appreciated.

<fx:mutter>if only [names deleted] in [place deleted] that I have to
work with paid as much attention and appreciated my efforts</fx:mutter>
--
Flash Gordon
May 4 '07 #49
mdh wrote, On 04/05/07 21:05:

<snip>
yes..I certainly see the general dislike for them on the clc. I think
I am going to remove p119 from K&R!!!
Don't deface a good book, just put in a slip of paper explaining the
problems.
--
Flash Gordon
May 4 '07 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: aitorf666 | last post by:
Hi! I have been looking for a comparison table of the relative cost of operations in C++ because it can be very useful for all. I have found this: printf/scanf 1000 new/delete 800 trig....
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.