473,402 Members | 2,072 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,402 software developers and data experts.

is const necessary in eg int compar(const void *, const void *)

Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)

If the pointer cannot be dereferenced why worry if the pointed object
will be modified?
Oct 15 '08 #1
28 2607
lo***************@gmail.c0m wrote:
Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)

If the pointer cannot be dereferenced why worry if the pointed object
will be modified?
Why can't the pointer be dereferenced?

--
Ian Collins
Oct 15 '08 #2
"lovecreatesbea...@gmail.c0m" <lovecreatesbea...@gmail.comwrote:
Is the keyword const necessary in the comparison function
in qsort and bsearch?
Not strictly necessary, but prudent.
int (*compar)(const void *, const void *)

If the pointer cannot be dereferenced why worry if the
pointed object will be modified?
When the pointer(s) are converted to the appropriate object
type, they certainly can be dereferenced, and usually are.

--
Peter
Oct 15 '08 #3
On Oct 15, 10:55 am, Peter Nilsson <ai...@acay.com.auwrote:
"lovecreatesbea...@gmail.c0m" <lovecreatesbea...@gmail.comwrote:
Is the keyword const necessary in the comparison function
in qsort and bsearch?

Not strictly necessary, but prudent.
int (*compar)(const void *, const void *)
If the pointer cannot be dereferenced why worry if the
pointed object will be modified?

When the pointer(s) are converted to the appropriate object
type, they certainly can be dereferenced, and usually are.
Thank you.

I ignored this, the const qualifier on the original pointers will
still require the same qulifier to be applied on those appropriate
object.
Oct 15 '08 #4
lo***************@gmail.c0m said:
Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)
Yes.
If the pointer cannot be dereferenced why worry if the pointed object
will be modified?
The pointer *can* be dereferenced after conversion to the appropriate type.
For example, look at all the dereferencing going on here:

#include <time.h>

int cmp_tm(const void *vleft, const void *vright)
{
const struct tm *left = vleft;
const struct tm *right = vright;
int diff =
(left->tm_year right->tm_year) - (left->tm_year < right->tm_year);
if(0 == diff)
{
diff =
(left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
}
if(0 == diff)
{
diff =
(left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
}
/* hour, min, sec similarly */

return diff;
}
--
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
Oct 15 '08 #5
On Oct 15, 11:16*am, Richard Heathfield <r...@see.sig.invalidwrote:
lovecreatesbea...@gmail.c0m said:
If the pointer cannot be dereferenced why worry if the pointed object
will be modified?

The pointer *can* be dereferenced after conversion to the appropriate type.
For example, look at all the dereferencing going on here:
Yes, thanks. I got it.
* if(0 == diff)
* {
* * diff =
* * (left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
* }
* if(0 == diff)
* {
* * diff =
* * (left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
* }
why don't you put your code together and create another same selection
block :)
Oct 15 '08 #6
lo***************@gmail.c0m said:
On Oct 15, 11:16 am, Richard Heathfield <r...@see.sig.invalidwrote:
>lovecreatesbea...@gmail.c0m said:
If the pointer cannot be dereferenced why worry if the pointed object
will be modified?

The pointer *can* be dereferenced after conversion to the appropriate
type. For example, look at all the dereferencing going on here:

Yes, thanks. I got it.
>if(0 == diff)
{
diff =
(left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
}
if(0 == diff)
{
diff =
(left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
}

why don't you put your code together and create another same selection
block :)
I haven't the faintest idea what you're talking about.

--
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
Oct 15 '08 #7
"lo***************@gmail.c0m" <lo***************@gmail.comwrites:
On Oct 15, 10:55 am, Peter Nilsson <ai...@acay.com.auwrote:
>"lovecreatesbea...@gmail.c0m" <lovecreatesbea...@gmail.comwrote:
Is the keyword const necessary in the comparison function
in qsort and bsearch?

Not strictly necessary, but prudent.
int (*compar)(const void *, const void *)
If the pointer cannot be dereferenced why worry if the
pointed object will be modified?

When the pointer(s) are converted to the appropriate object
type, they certainly can be dereferenced, and usually are.

Thank you.

I ignored this, the const qualifier on the original pointers will
still require the same qulifier to be applied on those appropriate
object.
Hmm, but wait a minute. I think your original point was valid.

For a function like

void foo(const int *p) { /* ... */ }

the compiler will complain if you attempt to assign to, or otherwise
modify, *p. So the compiler helps you make good on the promise you're
making to the caller, that *p will not be modified; this is the whole
point of const. You could circumvent this by assigning to *(int *)p,
but at least the fact that you had to introduce a cast serves as warning
that you might be doing something wrong.

But for a function like

void bar(const void *p) { /* ... */ }

where p is known to point to an int, you *have* to cast p before you can
do much with it. And if you're going to cast it, you could just as
easily cast it to `int *' as to `const int *', and the compiler will (in
my tests) remain silent either way. So the help you get from using
const is much less.

Now if we also have

void qux(void *);

and `bar' attempts to call `qux(p)', the compiler does whine. (This in
fact is exactly the whine that occurs if you pass a function taking
`void *' arguments to `qsort'.) But certainly a lot of the protection
has been lost. One could argue that this makes the use of
`const void *' sort of pointless, but if nothing else it provides some
documentation, I suppose.
Oct 15 '08 #8
Nate Eldredge said:

<snip>
But for a function like

void bar(const void *p) { /* ... */ }

where p is known to point to an int, you *have* to cast p before you can
do much with it.
Not so:

#include <stdio.h>

void bar(const void *p)
{
const int *pi = p;
printf("%d\n", *pi);
} /* look, ma, no casts */

--
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
Oct 15 '08 #9
lo***************@gmail.c0m wrote:
On Oct 15, 11:16 am, Richard Heathfield <r...@see.sig.invalidwrote:
>lovecreatesbea...@gmail.c0m said:
>>If the pointer cannot be dereferenced why worry if the pointed object
will be modified?
The pointer *can* be dereferenced after conversion to the appropriate type.
For example, look at all the dereferencing going on here:

Yes, thanks. I got it.
> if(0 == diff)
{
diff =
(left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
}
if(0 == diff)
{
diff =
(left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
}

why don't you put your code together and create another same selection
block :)
If the value of diff was 0 at the first if(), then diff gets
recalculated, in which case it might be non-0 for the second if(), so
you can't combine the two blocks into a single if() block.
Oct 15 '08 #10
Richard Heathfield wrote:
lo***************@gmail.c0m said:
>Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)

Yes.
Well, either "yes" or "no" depending on what "necessary" means.

Yes, it is "necessary," because qsort() and bsearch() specify
`const' as part of the signature of the comparison function they
call. If you try to pass a pointer to a function with a different
signature, the compiler will complain and may reject your code. So
`const' is "necessary" if you want to be sure the code compiles.

No, it is not "necessary," as shown by the fact that qsort() and
bsearch() existed and worked just fine before `const' was invented.
(Of course, they weren't exactly qsort() and bsearch() as we now
know them, because their declarations differed from today's versions.
Still, they were work-alikes and were used just as today's are.)
Without `const' and without prototypes to put it in, the primordial
functions required the programmer to "get it right" without the help
of compiler complaints to warn when something was wrong. However,
it was possible to "get it right" even without assistance, and in
that sense `const' was not a "necessary" addition to the functions'
signatures.

If your code is correct, you can remove every `const' and it
will still be correct and its meaning will be unchanged (imagine
that the removal also magically affects the Standard library).
The value of `const' is that when you add it "correctly" it can
change run-time errors to compile-time errors.

--
Er*********@sun.com
Oct 15 '08 #11
Eric Sosman said:
Richard Heathfield wrote:
>lo***************@gmail.c0m said:
>>Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)

Yes.

Well, either "yes" or "no" depending on what "necessary" means.

Yes, it is "necessary," because qsort() and bsearch() specify
`const' as part of the signature of the comparison function they
call.
Right.
If you try to pass a pointer to a function with a different
signature, the compiler will complain and may reject your code. So
`const' is "necessary" if you want to be sure the code compiles.
Right again.
No, it is not "necessary," as shown by the fact that qsort() and
bsearch() existed and worked just fine before `const' was invented.
My answer was written in the context of standard C.

<snip>

--
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
Oct 15 '08 #12
On 15 Oct 2008 at 8:45, Richard Heathfield wrote:
I'm of the opinion that it's always possible, and usually preferable,
to avoid casting.
As usual, your blind dogmatism leads you to talk nonsense.

A couple of trivial examples that come quickly to mind:

1) When passing a NULL pointer to variadic functions, you need an
explicit cast, e.g.
s = mystrconcat("hello", " ", "world", "!", (char *) NULL);

2) If you have a type that you know is an integer type but is typedef'd
in a system-specific header, then to portably print it you need a cast
to the widest integer type:

opaque_integer_type i = somefunction(42);
printf("The answer is %llu\n", (unsigned long long) i);

Oct 15 '08 #13
In article <sl*******************@nospam.invalid>,
Antoninus Twink <no****@nospam.invalidwrote:
>1) When passing a NULL pointer to variadic functions, you need an
explicit cast, e.g.
s = mystrconcat("hello", " ", "world", "!", (char *) NULL);
I'm sure someone will point out how it *can* be done without a cast,
but of course a cast is the natural way to do it.
>2) If you have a type that you know is an integer type but is typedef'd
in a system-specific header, then to portably print it you need a cast
to the widest integer type:

opaque_integer_type i = somefunction(42);
printf("The answer is %llu\n", (unsigned long long) i);
Alternatively the implementor can provide a macro for a format string,
as C99 does (PRIdMAX etc).

-- Richard

--
Please remember to mention me / in tapes you leave behind.
Oct 15 '08 #14
Richard Heathfield wrote:
Eric Sosman said:
>Richard Heathfield wrote:
>>lo***************@gmail.c0m said:

Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)
Yes.
Well, either "yes" or "no" depending on what "necessary" means.

Yes, it is "necessary," because qsort() and bsearch() specify
`const' as part of the signature of the comparison function they
call.
[...]
No, it is not "necessary," as shown by the fact that qsort() and
bsearch() existed and worked just fine before `const' was invented.

My answer was written in the context of standard C.
... which does not define "necessary." My answer tried to
address two of the meanings the O.P might have intended: "Necessary"
because That's Just The Way It Is, or "necessary" for a deeper reason.
Was the Committee obliged to add `const' to qsort() and bsearch()?
I think not. But since they chose to do so, programmers *are* now
obliged to use them in the manner the Committee chose.

Contrast this with another design decision the Committee made:
"How many arguments should qsort() take?" Since the Committee was
charged to codify existing practice, the answer "four" was forced
upon them; the necessity arose externally and the Committee passed it
along. But making the comparison function's parameters `const' was
something the Committee did of its own volition, not something they
did because it was "necessary."

--
Er*********@sun.com
Oct 15 '08 #15
Richard Tobin said:
In article <sl*******************@nospam.invalid>,
Antoninus Twink <no****@nospam.invalidwrote:
>>1) When passing a NULL pointer to variadic functions, you need an
explicit cast, e.g.
s = mystrconcat("hello", " ", "world", "!", (char *) NULL);

I'm sure someone will point out how it *can* be done without a cast,
Mr Twink is wrong on technical grounds and sub-optimal on stylistic
grounds: firstly, you *don't* need a cast, and secondly, "explicit" is
redundant.
but of course a cast is the natural way to do it.
Yes. I don't think anyone has claimed otherwise.
>>2) If you have a type that you know is an integer type but is typedef'd
in a system-specific header, then to portably print it you need a cast
to the widest integer type:

opaque_integer_type i = somefunction(42);
printf("The answer is %llu\n", (unsigned long long) i);

Alternatively the implementor can provide a macro for a format string,
as C99 does (PRIdMAX etc).
Yes. But if the type is opaque and not supported by the implementation, the
cast is in any case unwise. Instead, you should pass the value to the
opaque type's stream-writing function.

--
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
Oct 15 '08 #16
Richard Heathfield <rj*@see.sig.invalidwrites:
Richard Tobin said:
>In article <sl*******************@nospam.invalid>,
Antoninus Twink <no****@nospam.invalidwrote:
>>>1) When passing a NULL pointer to variadic functions, you need an
explicit cast, e.g.
s = mystrconcat("hello", " ", "world", "!", (char *) NULL);

I'm sure someone will point out how it *can* be done without a cast,

Mr Twink is wrong on technical grounds and sub-optimal on stylistic
grounds: firstly, you *don't* need a cast, and secondly, "explicit" is
redundant.
You're thinking of something like

char *n = NULL;
s = mystrconcat("hello", " ", "world", "!", n);

I assume?
>but of course a cast is the natural way to do it.

Yes. I don't think anyone has claimed otherwise.
>>>2) If you have a type that you know is an integer type but is typedef'd
in a system-specific header, then to portably print it you need a cast
to the widest integer type:

opaque_integer_type i = somefunction(42);
printf("The answer is %llu\n", (unsigned long long) i);

Alternatively the implementor can provide a macro for a format string,
as C99 does (PRIdMAX etc).

Yes. But if the type is opaque and not supported by the implementation, the
cast is in any case unwise. Instead, you should pass the value to the
opaque type's stream-writing function.
It's a pleasant world you live in where such things always exist. :)

Unix, for instance, is rife with integer types that don't come with
output functions. pid_t, uid_t, half the fields of struct stat, etc.
So I tend to do

printf("The file has inode number %ju\n", (uintmax_t)st.st_ino);

(st.st_ino has type `ino_t').

Of course, I can avoid the cast by saying

uintmax_t inode = st.st_ino;
printf("The file has inode number %ju\n", inode);

Oct 15 '08 #17
On Oct 15, 6:21 pm, James Kuyper <jameskuy...@verizon.netwrote:
lovecreatesbea...@gmail.c0m wrote:
On Oct 15, 11:16 am, Richard Heathfield <r...@see.sig.invalidwrote:
lovecreatesbea...@gmail.c0m said:
If the pointer cannot be dereferenced why worry if the pointed object
will be modified?
The pointer *can* be dereferenced after conversion to the appropriate type.
For example, look at all the dereferencing going on here:
Yes, thanks. I got it.
if(0 == diff)
{
diff =
(left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
}
if(0 == diff)
{
diff =
(left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
}
why don't you put your code together and create another same selection
block :)

If the value of diff was 0 at the first if(), then diff gets
recalculated, in which case it might be non-0 for the second if(), so
you can't combine the two blocks into a single if() block.- Hide quoted text -
Yes, but I don't think the original code is a good piece.


On Oct 15, 11:16 am, Richard Heathfield <r...@see.sig.invalidwrote:
>
#include <time.h>

int cmp_tm(const void *vleft, const void *vright)
{
const struct tm *left = vleft;
const struct tm *right = vright;
int diff =
(left->tm_year right->tm_year) - (left->tm_year < right->tm_year);
if(0 == diff)
{
diff =
(left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
}
if(0 == diff)
{
diff =
(left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
}
/* hour, min, sec similarly */

return diff;

}
#include <time.h>

int cmp_tm(const void *v1, const void *v2)
{
const struct tm *t1 = v1;
const struct tm *t2 = v2;
int diff_y, diff_m, diff_d;

diff_y = t1->tm_year != t2->tm_year;
diff_m = t1->tm_mon != t2->tm_mon;
diff_d = t1->tm_mday != t2->tm_mday;

if (!diff_y && !diff_m){
/* usage of diff_d; */
}

/* hour, min, sec similarly */

return diff_d; /*diff in sec maybe*/
}
Oct 15 '08 #18
lo***************@gmail.c0m wrote:
>
is it better to use this simple line:
d[0] = t1->tm_year - t2->tm_year;

instead of Richard Heathfield's:
diff = (left->tm_year right->tm_year) - (left->tm_year < right-
>tm_year);
Richard's technique is intended to remove the risk of integer over
(under?) flow.

--
Ian Collins
Oct 16 '08 #19
jaysome said:
On Wed, 15 Oct 2008 08:45:29 +0000, Richard Heathfield
<rj*@see.sig.invalidwrote:
<snip>
>>I'm of the opinion that it's always possible, and usually preferable, to
avoid casting.

If p is of any type other than void *, can (and should) this cast be
avoided?

printf("p = %p\n", (void*)p);
Can - yes, by using a temp. Should? That's a question of style.

--
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
Oct 25 '08 #20
jaysome wrote:
>
.... snip ...
>
If p is of any type other than void *, can (and should) this cast
be avoided?

printf("p = %p\n", (void*)p);
The variadic functions, in particular printf and clones, are
glaring examples of exceptions to the general rule "casts are
errors". The reason is that the only type information such
functions have is the construct of the format string, which is not
generally known at compile time (the format string may be a
variable).

In your example, above, the %p has specified that the functions is
receiving a void* parameter. So, if p is not of this type, you
have to convert it with a cast. A good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 25 '08 #21
CBFalconer <cb********@yahoo.comwrites:

<snip>
... A good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.
What is "illegal" about it? The conversion is implementation defined,
but illegal seems way too strong a word.

--
Ben.
Oct 26 '08 #22
On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
CBFalconer <cbfalco...@yahoo.comwrites:

<snip>
... A good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.

What is "illegal" about it? The conversion is implementation defined,
but illegal seems way too strong a word.
The conversion is implementation defined, and one of the possible
behaviors is undefined behavior.
If something is UB on an imaginary implementation it's a good enough
reason for me to avoid that 'something'.
Chuck could've just been more clear by using a term defined in the
standard.

Oct 27 '08 #23
On 27 Oct, 21:24, vipps...@gmail.com wrote:
On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
CBFalconer <cbfalco...@yahoo.comwrites:
... *A good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.
What is "illegal" about it? *The conversion is implementation defined,
but illegal seems way too strong a word.

The conversion is implementation defined, and one of the possible
behaviors is undefined behavior.
I didn't think that was so. I thought Implementation Defined
actually had to be defined by the implementation. And that the
standard usually (nearly always?) gave a narrow range of
possibilities.

<find standard>

Para 3.3.4 "Cast Operators"
[...]
"A pointer may be converted to an integral type. The size of
integer required and the result is implementaion-defined. If
the space provided is not long enough, the behaviour is
undefined"

Seems to be having it both ways...

The Rationale has this to say:

"Nothing portable can be said about casting integers to pointers,
or vice versa, since the two are now incommensurate."

which sounds very like UB to me...

If something is UB on an imaginary implementation it's a good enough
reason for me to avoid that 'something'.
Chuck could've just been more clear by using a term defined in the
standard.

--
Nick Keighley

1,3,7-trimethylxanthine -- a basic ingredient in quality software.
Oct 28 '08 #24
Nick Keighley wrote:
On 27 Oct, 21:24, vipps...@gmail.com wrote:
On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
CBFalconer <cbfalco...@yahoo.comwrites:
... �A good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.
What is "illegal" about it? �The conversion is implementationdefined,
but illegal seems way too strong a word.
The conversion is implementation defined, and one of the possible
behaviors is undefined behavior.

I didn't think that was so. I thought Implementation Defined
actually had to be defined by the implementation. And that the
standard usually (nearly always?) gave a narrow range of
possibilities.
It does, sort of:

6.3.2.3p5: "An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might not
be correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation."

For void*, the possibility of incorrect alignment is not a problem.
Its not even possible for the resulting pointer to point to an entity
of the referenced type, so that's not an issue, either. The problem is
the last item on the list of possibilities. There's no problem if the
implementation-defined behavior does not include trap representations,
but portable code cannot make any such assumption. The behavior is
undefined if you store the result of such a conversion in an object.

It is an oddity of the standard that the possible result of a
conversion, which is a value, is referred to as a "representation",
something that can only be stored in an object. All the nasty things
that the standard says explicitly about trap representations apply
only if you try to store them in an object using an lvalue of pointer
type, or if you use an object that has had such had such a
representation created in it by other means. This would seem to imply
that it should be perfectly safe to make use of a trap representation
returned by a conversion, so long as you don't use it any way that
would otherwise result in it being stored in an object. However, I
strongly suspect that you can produce an argument that it is
implicitly undefined behavior to do anything with such a trap
representation, due to lack of an explicit definition of the behavior.
Oct 28 '08 #25
jameskuyper <ja*********@verizon.netwrites:
Nick Keighley wrote:
On 27 Oct, 21:24, vipps...@gmail.com wrote:
On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
CBFalconer <cbfalco...@yahoo.comwrites:
... =EF=BF=BDA good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.
>
What is "illegal" about it? =EF=BF=BDThe conversion is implementation=
defined,
but illegal seems way too strong a word.
>
The conversion is implementation defined, and one of the possible
behaviors is undefined behavior.
I didn't think that was so. I thought Implementation Defined
actually had to be defined by the implementation. And that the
standard usually (nearly always?) gave a narrow range of
possibilities.

It does, sort of:

6.3.2.3p5: "An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might not
be correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation."

For void*, the possibility of incorrect alignment is not a problem.
Its not even possible for the resulting pointer to point to an entity
of the referenced type, so that's not an issue, either. The problem is
the last item on the list of possibilities. There's no problem if the
implementation-defined behavior does not include trap representations,
but portable code cannot make any such assumption. The behavior is
undefined if you store the result of such a conversion in an object.

It is an oddity of the standard that the possible result of a
conversion, which is a value, is referred to as a "representation",
something that can only be stored in an object. All the nasty things
that the standard says explicitly about trap representations apply
only if you try to store them in an object using an lvalue of pointer
type, or if you use an object that has had such had such a
representation created in it by other means. This would seem to imply
that it should be perfectly safe to make use of a trap representation
returned by a conversion, so long as you don't use it any way that
would otherwise result in it being stored in an object. However, I
strongly suspect that you can produce an argument that it is
implicitly undefined behavior to do anything with such a trap
representation, due to lack of an explicit definition of the behavior.
Yes; it's a simple argument.

Any attempt to use the value of a trap representation (using the
type where it's a trap representation) certainly should be
undefined behavior, since trap representations don't represent a
value of that type. The Standard is quite clear about this:
the absence of definition means undefined behavior just the same
as if it were labelled undefined behavior.

Arguably a trap representation evaluated as a (void) expression
doesn't have its value used, so this might be okay. But anywhere
else a trap representation occurs in a value context, including
further conversion, needs to use the value and hence is undefined
behavior.
Nov 9 '08 #26
Tim Rentsch wrote:
jameskuyper <ja*********@verizon.netwrites:
>Nick Keighley wrote:
.... snip ...
>>
>>I didn't think that was so. I thought Implementation Defined
actually had to be defined by the implementation. And that the
standard usually (nearly always?) gave a narrow range of
possibilities.

It does, sort of:
.... snip ...
>
Yes; it's a simple argument.
The point is that 'implementation defined' is not universal. One
implementation may define it one way, another in some other
manner. So you can't count on code that invokes that.

Thus using it is not portable C. And portable C, as defined by the
C standard, is the subject of discussion on c.l.c. If you go to a
newsgroup that deals with _your_ system, it will be topical.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Nov 9 '08 #27
Eric Sosman <Er*********@sun.comwrites:
Richard Heathfield wrote:
lo***************@gmail.c0m said:
Is the keyword const necessary in the comparison function in qsort and
bsearch?

int (*compar)(const void *, const void *)
Yes.

Well, either "yes" or "no" depending on what "necessary" means.

Yes, it is "necessary," because qsort() and bsearch() specify
`const' as part of the signature of the comparison function they
call. If you try to pass a pointer to a function with a different
signature, the compiler will complain and may reject your code. So
`const' is "necessary" if you want to be sure the code compiles.
[...]
I'm sure a lot of readers know this but for those that don't...

In C the correct term is "type" and not "signature". The term
"signature" comes from the programming language Russell, where
it's important to use a word different from "type" because "type"
means something different in Russell (related to the common
meaning of type, but still significantly different).

It's common in programming language circles to use the word
"signature" rather than "type" (especially when talking about
functions, for some reason), even when "type" is adequate and also
more accurate in the sense that it reflects the terminology used
by the programming language under discussion. I don't know why
people do this; my guess is because it sounds like it's more
precise or perhaps more grounded in some formal theoretical
framework. Neither of those is true, by the way.

There is an important sense in which "signature" is inappropriate
for C, in that functions in Russell (with signatures) are more
powerful than functions in C (with types). In particular, a
function in Russell admits parameters that are abstract data types
(what Russell calls a "type"); thus a function in Russell is like
a function template in C++, except that unlike templates in C++ a
function in Russell doesn't need to be instantiated to be used
with different type parameters -- in Russell abstract data types
are values and can be used just like ordinary values (such as int)
can. C doesn't admit abstract data types as values or parameters.

So if you're talking to someone about C and the term "signature"
comes up, it might be a good idea to ask "Do you mean type, or
are you talking about a different language?"

None of the above is intended as any kind of comment on Mr. Sosman,
who in my experience is both a gracious guy and a generally smart
fellow.
Nov 10 '08 #28
CBFalconer <cb********@yahoo.comwrites:
Tim Rentsch wrote:
jameskuyper <ja*********@verizon.netwrites:
Nick Keighley wrote:
... snip ...
>
I didn't think that was so. I thought Implementation Defined
actually had to be defined by the implementation. And that the
standard usually (nearly always?) gave a narrow range of
possibilities.

It does, sort of:
... snip ...

Yes; it's a simple argument.

The point is that 'implementation defined' is not universal. One
implementation may define it one way, another in some other
manner. So you can't count on code that invokes that.

Thus using it is not portable C. And portable C, as defined by the
C standard, is the subject of discussion on c.l.c. If you go to a
newsgroup that deals with _your_ system, it will be topical.
If you read my posting (repeated below) again, I think you'll see
that it's a response to a sub-comment made by James Kuyper about
trap representations, and doesn't have anything to do with
implementation-defined behavior. I left in the earlier material,
about implementation-defined behavior, to help provide context;
I'm sorry if it being left in confused you.
ORIGINAL POSTING:

jameskuyper <ja*********@verizon.netwrites:
Nick Keighley wrote:
On 27 Oct, 21:24, vipps...@gmail.com wrote:
On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
CBFalconer <cbfalco...@yahoo.comwrites:
... =EF=BF=BDA good compiler will at least tell
you if you are making an illegal cast, such as casting an integer
to a void*.
>
What is "illegal" about it? =EF=BF=BDThe conversion is implementation=
defined,
but illegal seems way too strong a word.
>
The conversion is implementation defined, and one of the possible
behaviors is undefined behavior.
I didn't think that was so. I thought Implementation Defined
actually had to be defined by the implementation. And that the
standard usually (nearly always?) gave a narrow range of
possibilities.

It does, sort of:

6.3.2.3p5: "An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might not
be correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation."

For void*, the possibility of incorrect alignment is not a problem.
Its not even possible for the resulting pointer to point to an entity
of the referenced type, so that's not an issue, either. The problem is
the last item on the list of possibilities. There's no problem if the
implementation-defined behavior does not include trap representations,
but portable code cannot make any such assumption. The behavior is
undefined if you store the result of such a conversion in an object.

It is an oddity of the standard that the possible result of a
conversion, which is a value, is referred to as a "representation",
something that can only be stored in an object. All the nasty things
that the standard says explicitly about trap representations apply
only if you try to store them in an object using an lvalue of pointer
type, or if you use an object that has had such had such a
representation created in it by other means. This would seem to imply
that it should be perfectly safe to make use of a trap representation
returned by a conversion, so long as you don't use it any way that
would otherwise result in it being stored in an object. However, I
strongly suspect that you can produce an argument that it is
implicitly undefined behavior to do anything with such a trap
representation, due to lack of an explicit definition of the behavior.
Yes; it's a simple argument.

Any attempt to use the value of a trap representation (using the
type where it's a trap representation) certainly should be
undefined behavior, since trap representations don't represent a
value of that type. The Standard is quite clear about this:
the absence of definition means undefined behavior just the same
as if it were labelled undefined behavior.

Arguably a trap representation evaluated as a (void) expression
doesn't have its value used, so this might be okay. But anywhere
else a trap representation occurs in a value context, including
further conversion, needs to use the value and hence is undefined
behavior.
Nov 10 '08 #29

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

Similar topics

1
by: john smith | last post by:
Hi, say I have a class like so: class A { public: virtual void foo(); void bar() const; }; so when I actually define foo() and bar(), do I have to re-type the virtual and const modifiers...
12
by: DeMarcus | last post by:
Hi, I have an object, let's call it HydraulicPress class HydraulicPress { public: void setIron( Iron* iron ) const; Iron* getIron( void ) const;
10
by: quantdev2004 | last post by:
Hi all, I have been deling with this kind of code: class Foo { public: void NonConstMethod() {} };
1
by: electric sheep | last post by:
Hi, can somebody explain the following syntax to me. This is straight from a gnu info file: int main(void) { /* Hashed form of "GNU libc manual". */ const char *const pass =...
6
by: bob_jenkins | last post by:
{ const void *p; (void)memset((void *)p, ' ', (size_t)10); } Should this call to memset() be legal? Memset is of type void *memset(void *, unsigned char, size_t) Also, (void *) is the...
16
by: hzmonte | last post by:
Correct me if I am wrong, declaring formal parameters of functions as const, if they should not be/is not changed, has 2 benefits; 1. It tells the program that calls this function that the...
7
by: Bala L | last post by:
I have a class with a private array data member 'm_array'. I have written a public function, called 'fileRead', to read values into the array from a file. I just noticed that I have declared this...
4
by: grizggg | last post by:
I have searched and not found an answer to this question. I ran upon the following statement in a *.cpp file in a member function: static const char * const pacz_HTMLContentTypeHeader =...
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?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
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
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,...
0
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...
0
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...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.