473,847 Members | 1,561 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Function pointer question P119 K&R

mdh
May I ask the following.

By K&R's own admission, the example used to describe function pointers
is complex ( on P119). In addition, the use of casts has been stated
by some on this group as being, again, a poor/bad example of it's use.
For the moment, accepting these criticisms, I would still like to get
some insight into why/how some things work as even poor code is
enlightening, to me at least.

The example uses K&R's version of qsort ( not the standard one) and
the declaration is as follows:

void qsort(void *lineptr[], int left, int right. int (*comp)(void *,
void *));

The example then chooses from one of 2 methods for comparing strings,
whose declaration are:

int numcmp (*char, *char);
int strcmp( *char, *char);

The call to qsort is as follows:

qsort (void**)lineptr , 0, nlines-1, int (*)(void*, void*)) numeric?
numcmp:strcm)); /* numeric is an integer set based on an optional
command line argument) */

One last declaration before my question.

The swap function is declared as:

void swap(void *[], int, int);

Within the qsort function, the call to the function pointer is as
follows:

if ((*comp)(v[i], v[left] ) < 0)
swap (v, ++last, i);

If qsort casts the comparison function to void pointers, as it does in
"main", then why is it ok for the call in qsort to pass as arguments
to void pointers when the functions numcmp/strcmp expect as arguments
2 char pointers? Or..I might be totally confusing the issue, which is
equally likely. Swap seems to act as I would expect, ie it receives as
it's arguments, an array of pointers to void, plus 2 integers.

thanks in advance.
Jul 9 '08 #1
18 2652
mdh <md**@comcast.n etwrites:

<snip>
The example uses K&R's version of qsort ( not the standard one) and
the declaration is as follows:

void qsort(void *lineptr[], int left, int right. int (*comp)(void *,
void *));

The example then chooses from one of 2 methods for comparing strings,
whose declaration are:

int numcmp (*char, *char);
int strcmp( *char, *char);

The call to qsort is as follows:

qsort (void**)lineptr , 0, nlines-1, int (*)(void*, void*)) numeric?
numcmp:strcm)); /* numeric is an integer set based on an optional
command line argument) */

One last declaration before my question.

The swap function is declared as:

void swap(void *[], int, int);

Within the qsort function, the call to the function pointer is as
follows:

if ((*comp)(v[i], v[left] ) < 0)
swap (v, ++last, i);
We now have v. The prototype you showed had lineptr. I'll assume the
v is a void ** like lineptr.
If qsort casts the comparison function to void pointers, as it does in
"main", then why is it ok for the call in qsort to pass as arguments
to void pointers when the functions numcmp/strcmp expect as arguments
2 char pointers?
It is not OK (in general). It works in practise because void * and
char * must have the same size and representation but if the lineptr
array were, say, an array of struct pointers it might very well fail
on a real machine (albeit an old one).

You can convert a function pointer to any type of function pointer you
like but to be safe, when you call it, you have converted it back to
(a pointer to) the type of the function you are actually calling and
you must pass arguments that are "acceptable " as per the normal
function call rules. I say "acceptable " because the exact rules are
rather wordy and are not really the subject of our question.
Or..I might be totally confusing the issue, which is
equally likely. Swap seems to act as I would expect, ie it receives as
it's arguments, an array of pointers to void, plus 2 integers.
Yes, the call to swap is fine.

--
Ben.
Jul 9 '08 #2
m
In article <87************ @bsb.me.uk>,
Ben Bacarisse <be********@bsb .me.ukwrote:

>
We now have v. The prototype you showed had lineptr. I'll assume the
v is a void ** like lineptr.
If qsort casts the comparison function to void pointers, as it does in
"main", then why is it ok for the call in qsort to pass as arguments
to void pointers when the functions numcmp/strcmp expect as arguments
2 char pointers?

It is not OK (in general). It works in practise because void * and
char * must have the same size and representation but if the lineptr
array were, say, an array of struct pointers it might very well fail
on a real machine (albeit an old one).
Ben, you say that void * and char * must have the same size and
representation. Are you saying that this is a fact in C, or are you
saying that it must be so for the program to work as intended and it is
up to the programmer to ensure that this fact is true.
Jul 9 '08 #3
m said:

<snip>
Ben, you say that void * and char * must have the same size and
representation. Are you saying that this is a fact in C,
It's a fact in C.

Buried deep in 3.1.2.5 we find that "A pointer to void shall have the same
representation and alignment requirements as a pointer to a character
type. Other pointer types need not have the same representation or
alignment requirements."

--
Richard Heathfield <http://www.cpax.org.uk >
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 9 '08 #4
m wrote:
In article <87************ @bsb.me.uk>,
Ben Bacarisse <be********@bsb .me.ukwrote:

>>
We now have v. The prototype you showed had lineptr. I'll assume
the v is a void ** like lineptr.
If qsort casts the comparison function to void pointers, as it does
in "main", then why is it ok for the call in qsort to pass as
arguments to void pointers when the functions numcmp/strcmp expect
as arguments 2 char pointers?

It is not OK (in general). It works in practise because void * and
char * must have the same size and representation but if the lineptr
array were, say, an array of struct pointers it might very well fail
on a real machine (albeit an old one).

Ben, you say that void * and char * must have the same size and
representation. Are you saying that this is a fact in C, or are you
saying that it must be so for the program to work as intended and it
is up to the programmer to ensure that this fact is true.
No, it is required by the Standard. This was because before
Standardisation , char* was often used as a "generic" pointer type. The
Standard codified a separate type for this (void*), but to maintain
compatibility with pre-Standard code and ease the transition to
Standard C, it retained this property of char* too.

IIRC K&R2 explains this in appendix A.

Jul 9 '08 #5
m
In article <ba************ *************** ***@bt.com>,
Richard Heathfield <rj*@see.sig.in validwrote:
m said:

<snip>
Ben, you say that void * and char * must have the same size and
representation. Are you saying that this is a fact in C,

It's a fact in C.
Thank you Richard. At some point...I would really like to hear your
take on the issue of the misuse of casts.

BTW...I am not sure if you have noticed how little traffic there
is...Google is totally messed up...about 18 hours behind.
Jul 9 '08 #6
m
In article <g5**********@r egistered.motza rella.org>,
santosh <sa*********@gm ail.comwrote:
>
It is not OK (in general). It works in practise because void * and
char * must have the same size and representation but if the lineptr
array were, say, an array of struct pointers it might very well fail
on a real machine (albeit an old one).
>
No, it is required by the Standard. This was because before
Standardisation , char* was often used as a "generic" pointer type. The
Standard codified a separate type for this (void*), but to maintain
compatibility with pre-Standard code and ease the transition to
Standard C, it retained this property of char* too.

IIRC K&R2 explains this in appendix A.

Thank you Santosh...not quite at the appendix yet!
Jul 9 '08 #7
On Jul 9, 5:10*am, mdh <m...@comcast.n etwrote:
int numcmp (*char, *char);
int strcmp( *char, *char);
int numcmp(char *, char *);
int strcmp(char *, char *);

>
qsort (void**)lineptr , 0, nlines-1, int (*)(void*, void*)) numeric?
numcmp:strcm));
I assume you meant it to be:
qsort ((void**)linept r, 0, nlines-1, (int (*)(void*, void*)) (numeric?
numcmp:strcm));
>
If qsort casts the comparison function to void pointers, as it does in
"main",
qsort is casting the function pointer to a pointer to a function
taking 2 pointer to a void parameters and returning int.
to void pointers when the functions numcmp/strcmp expect as arguments
2 char pointers?
char and void pointers are required to have compatible representation.
Still, the correct way to do it is to declare numcmp as taking void *
and cast it in the function itself.

int numcmp(void *foo, void *bar) {
return *(int *)foo - *(int *)bar;
}

Jul 9 '08 #8
rahul said:

<snip>
Still, the correct way to do it is to declare numcmp as taking void *
and cast it in the function itself.

int numcmp(void *foo, void *bar) {
return *(int *)foo - *(int *)bar;
No, qsort takes int(*)(const void *, const void *), not int (*)(void *,
void *).

And there's no need for a cast if you don't want one. And there's no need
to risk overflow, either.

int numcmp(const void *vleft, const void *vright)
{
const int *left = vleft;
const int *right = vright;
return (*left *right) - (*left < *right);
}

Note, however, that K&R2's comparison routine takes string inputs, so we
would instead need:

#include <stdlib.h>
int numcmp(const void *vleft, const void *vright)
{
const char *sleft = vleft;
const char *sright = vright;
double left = strtod(sleft, NULL);
double right = strtod(sright, NULL);
return (left right) - (left < right);
}

K is a marvellous chap and all that, but he's just a bit too fond of casts
for my taste.

--
Richard Heathfield <http://www.cpax.org.uk >
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 9 '08 #9
m <md**@comcast.n etwrites:
In article <ba************ *************** ***@bt.com>,
Richard Heathfield <rj*@see.sig.in validwrote:
>m said:

<snip>
Ben, you say that void * and char * must have the same size and
representation. Are you saying that this is a fact in C,

It's a fact in C.

Thank you Richard. At some point...I would really like to hear your
take on the issue of the misuse of casts.
But it is probably worth pointing out that the code is still a
technical violation. The wording about representations and alignment
mean that it is hard to see what an implementation could be doing that
would make the code go wrong but it is still, technically, UB:

6.5.2.2 p9: "If the function is defined with a type that is not
compatible with the type (of the expression) pointed to by the
expression that denotes the called function, the behavior is
undefined."

You need to read an awful lot to be sure, but the function types
pointed to by 'int (*)(void *, void *)' and 'int (*)(char *, char *)'
are not compatible -- even allowing for the special wording about char
* and void *.

--
Ben.
Jul 9 '08 #10

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

Similar topics

11
8111
by: Josh Lessard | last post by:
Hi all. I'm maintaining a C++ program and I've come across a nasty piece of code that works, but I just don't understand why. I'm not actually this part of the program, but I really want to know how and why it works. I'll post a simplified version of it below and ask my questions afterwards: class Base { void *function_ptr;
4
4219
by: WittyGuy | last post by:
Hi all, Though I know the concepts of both abstract class & virtual function (like derived class pointer pointing to base class...then calling the function with the pointer...), what is the real implementation usage of these concepts? Where these concepts will be used. Please provide some illustration (real-time), so that it can be easily comprehended. Thanks, wittyGuy
8
2948
by: pt | last post by:
Hallo, i wonder how it is going to be of this code below regarding of the return of temporary object. Prototypes: =========== bool Activation(TCHAR *c); std::basic_string<TCHAR> GetFile();
2
2183
by: dis | last post by:
The following code introduces a 'generic function pointer' p. When calling the pointed-to function via this p, one has to typecast p towards a pointer to the type of the pointed-to function. My question is how to do this if the pointed-to function is a K&R style declared function, like f. The best I could come up with is a typecast towards a pointer to a function with unspecified number and type of parameters (and appropriate return type),...
3
2558
by: Peter Goddard | last post by:
Hello, Is it possible, using casting to promote... void *Ptr; To behave like... void (*FnPtr)(void); ?
14
1962
by: Bryan Parkoff | last post by:
Do you know that current C++ Compiler limits to 64KB segments in source code? It is good news that Microsoft Visual C++ 2005 has expanded to 4GB segments in source code. 4GB segment is ideal for large object using pointer to function and switch. Please list other C++ Compilers if they have added a support of 4GB segments. I am able to write 65,536 functions and 65,536 function's memory address is stored into pointer to function list. ...
5
1699
by: Felix Kater | last post by:
Hi, if I want to make sure that neither the pointer arg nor the value to which it points to is NULL: Is solution (a) safe -- or does it have to be like (b) ? Felix void f(int* p){ /* (a) */
12
4652
by: ArunDhaJ | last post by:
Hi Friends, Is it possible to pass a table as a parameter to a funtion. whos function declaration would look some thing like this.... ALTER FUNCTION TempFunction (@TempTable TABLE, @nPId INT) my problem is: i have to access a temporary table created in an SP in a function
3
1617
by: Daniel Kraft | last post by:
Hi, I was curious whether or not to use the & operator when creating a function pointer. It seems, that both &func and plain func create a pointer of the appropriate function pointer type. However, for member function pointers it seems that the use of & is mandatory, the following code compiles but does not when uncommenting the initialization of c:
0
9892
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, weíll explore What is ONU, What Is Router, ONU & Routerís main usage, and What is the difference between ONU and Router. Letís take a closer look ! Part I. Meaning of...
0
9735
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10996
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10658
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10718
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10347
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7062
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5915
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
4133
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.