const type question

H

herrcho

int intcmp(const void *a, const void *b)
{
return (*(int*)a - *(int*)b);
}

in the above , if i put just 'void' instead of 'const void' as a
parameter,

what's the difference ?

i can't get the meaning of const when used in parameter..

Thanks in advance ~
 
R

Richard Bos

herrcho said:
int intcmp(const void *a, const void *b)
{
return (*(int*)a - *(int*)b);
}

in the above , if i put just 'void' instead of 'const void' as a
parameter,

what's the difference ?

Nothing, since you're not trying to change anything anyway.
i can't get the meaning of const when used in parameter..

If a parameter is declared const, the function cannot change it. This
sounds like it's no change, since a function cannot change a the value
of a parameter in the caller anyway. However, if the parameter is const,
the function cannot even change its value _within the function_.
If a parameter is a pointer to a const type, the function cannot change
the object the pointer points at.

If you don't modify anything in the function to begin with, this doesn't
matter, of course. However, the above looks like a comparison function
for qsort() (or bsearch()). In that case, the consts are there to
prevent you from changing the objects behind qsort()'s back, since doing
so could mess up the sorting algorithm.

Richard
 
S

Simon Biber

herrcho said:
int intcmp(const void *a, const void *b)
{
return (*(int*)a - *(int*)b);
}

in the above , if i put just 'void' instead of 'const void' as a
parameter,

what's the difference ?

If you're intending to pass this function to qsort or something
that expects a parameter of type int(*)(const void*,const void*)
then you must not change from const void to void, this will be
a constraint violation (wrong type of argument) or else undefined
behaviour (if you say cast it back to the right type).
i can't get the meaning of const when used in parameter..

When used as 'const type *a' it means that you are not allowed to
modify the thing that the pointer is pointing to. Unfortunately
due to the bad way you wrote the function this protection is lost
when you cast the argument to (int*). You can in fact write any
qsort compare function in a completely typesafe manner with no
casts, which is much cleaner code:

int intcmp(const void *va, const void *vb)
{
const int *a = va, *b = vb;
return *a - *b;
}

That way you will get a diagnostic message from the compiler if
you accidentally attempt to modify the contents of the memory.
 
C

CBFalconer

Simon said:
.... snip ...

When used as 'const type *a' it means that you are not allowed to
modify the thing that the pointer is pointing to. Unfortunately
due to the bad way you wrote the function this protection is lost
when you cast the argument to (int*). You can in fact write any
qsort compare function in a completely typesafe manner with no
casts, which is much cleaner code:

int intcmp(const void *va, const void *vb)
{
const int *a = va, *b = vb;
return *a - *b;
}

That way you will get a diagnostic message from the compiler if
you accidentally attempt to modify the contents of the memory.

Totally agree, EXCEPT for the actual comparison in your example,
which is liable to problems from integer overflow. This is a good
place for:

return (*a > *b) - (*a < *b);
 
S

Simon Biber

CBFalconer said:
Totally agree, EXCEPT for the actual comparison in your example,
which is liable to problems from integer overflow. This is a good
place for:

return (*a > *b) - (*a < *b);

Yes, my mistake. In fact I usually write it like the equivalent:
return (*a < *b) ? -1 : (*a > *b);

But I prefer your subtraction form, because in the rather arbitrary
and unjustified model of code microefficiency in my head, a subtract
is faster than a compare. This may or may not be true on any of the
platforms I compile for, I wouldn't know.
 
P

Peter Nilsson

Simon Biber said:
You can in fact write any
qsort compare function in a completely typesafe manner

How? The function itself can never guarantee that it won't be applied to a
type that differs from the intended one.
with no casts, which is much cleaner code:

Cleaner perhaps, but an absense of casts is not typesafety.
 
P

pete

Simon said:
Yes, my mistake. In fact I usually write it like the equivalent:
return (*a < *b) ? -1 : (*a > *b);

But I prefer your subtraction form, because in the rather arbitrary
and unjustified model of code microefficiency in my head, a subtract
is faster than a compare. This may or may not be true on any of the
platforms I compile for, I wouldn't know.

I see two unconditional comparisons and a subtraction
in the first,
but only two comparisons, with one of them being conditional,
in the second.
 
C

CBFalconer

pete said:
I see two unconditional comparisons and a subtraction in the first,
but only two comparisons, with one of them being conditional,
in the second.

However the emitted code will often not have any jumps in it (for
the first), which avoids flushing any instruction queues. I
learned it from someone, and consider it a trick worth knowing.

The point is that they are both safe, and have a chance to
simultaneously be efficient and clear. However there may be
considerable code involved in converting a machine comparison into
the 0 or 1 representation, in which case the ?: coding will be
superior.
 
P

pete

CBFalconer said:
However the emitted code will often not have any jumps in it (for
the first), which avoids flushing any instruction queues. I
learned it from someone, and consider it a trick worth knowing.

The point is that they are both safe, and have a chance to
simultaneously be efficient and clear. However there may be
considerable code involved in converting a machine comparison into
the 0 or 1 representation, in which case the ?: coding will be
superior.

Thank you.
 
D

dam_fool_2003

Simon Biber said:
If you're intending to pass this function to qsort or something
that expects a parameter of type int(*)(const void*,const void*)
then you must not change from const void to void, this will be
a constraint violation (wrong type of argument) or else undefined
behaviour (if you say cast it back to the right type).


When used as 'const type *a' it means that you are not allowed to
modify the thing that the pointer is pointing to. Unfortunately
due to the bad way you wrote the function this protection is lost
when you cast the argument to (int*). You can in fact write any
qsort compare function in a completely typesafe manner with no
casts, which is much cleaner code:

int intcmp(const void *va, const void *vb)
{
const int *a = va, *b = vb;
return *a - *b;
}
Friends,
Don't we have to cast a void* so that the void points to a valid
value (as per 6.3.2.3 of the standard). (Correct me if I am wrong):

int fun(const void *a, const void *b)
{
unsigned int *p , *q;
p =(unsigned int*) a, q =(unsigned int*) b;
/*return (*p > *q ) - (*p < *q); */
return *p - *q;
}
int main(void)
{
int a=2,b=2,c=8,d=6;
printf("%d %d\n",fun(&a,&b),fun(&c,&d));
return 0;
}

OUTPUT:

0 2

And for the second one:

int fun(const void *a, const void *b)
{
unsigned int *p , *q;
p =(unsigned int*) a, q =(unsigned int*) b;
return (*p > *q ) - (*p < *q);
/*return *p - *q; */
}
int main(void)
{
int a=2,b=2,c=8,d=6;
printf("%d %d\n",fun(&a,&b),fun(&c,&d));
return 0;
}

OUTPUT:
0 1

Is there any UB?
 
J

j

"Simon Biber" <[email protected]> wrote in message
Friends,
Don't we have to cast a void* so that the void points to a valid
value (as per 6.3.2.3 of the standard). (Correct me if I am wrong):

No, this isn't C++.

The standard states that:
``A pointer to void may be converted to or from a pointer to any incomplete
or object
type. A pointer to any incomplete or object type may be converted to a
pointer to void
and back again; the result shall compare equal to the original pointer.''


And for simple assignment(which also applies to initialization) that:
``One operand is a pointer to an object or incomplete type and the other
is a pointer to a qualified or unqualified version of void, and the type
pointed to by the left has all the qualifiers of the type pointed to by
the right''

Which makes casting in this case entirely unnecessary.

example.c:
#include <stdio.h>
int main(void)
{
unsigned int i;
unsigned int *p;
void *p1;

p = &i;
p1 = p;
p = p1;

if(p == p1)
puts("They compare equal.");
else
puts("Get a new compiler.");

return 0;
}
 
D

dam_fool_2003

j said:
No, this isn't C++.

I don't have C++ standard.I have the slandered ISO-C-1999-04, which
has got the same words as you mentioned.
The standard states that:
``A pointer to void may be converted to or from a pointer to any incomplete
or object
type. A pointer to any incomplete or object type may be converted to a
pointer to void
and back again; the result shall compare equal to the original pointer.''


And for simple assignment(which also applies to initialization) that:
``One operand is a pointer to an object or incomplete type and the other
is a pointer to a qualified or unqualified version of void, and the type
pointed to by the left has all the qualifiers of the type pointed to by
the right''

Which makes casting in this case entirely unnecessary.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, not in the above case with const void* in the parameter and
non-const with in the function scope.
 
J

j

"j" <[email protected]> wrote in message

I don't have C++ standard.I have the slandered ISO-C-1999-04, which
has got the same words as you mentioned.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, not in the above case with const void* in the parameter and
non-const with in the function scope.

Where is the type in the ``intcmp'' function which is not qualified by
const?
I can see two pointer to ints qualified by const being initialized with two
pointers to void which are also qualified by const.
 
K

Kevin Bracey

In message <[email protected]>

Actually, both cases will probably only need to have one actual comparison on
most architectures, with a multi-way set of conditions following.
However the emitted code will often not have any jumps in it (for
the first), which avoids flushing any instruction queues. I
learned it from someone, and consider it a trick worth knowing.

Isn't micro-optimisation great?
The point is that they are both safe, and have a chance to
simultaneously be efficient and clear. However there may be
considerable code involved in converting a machine comparison into
the 0 or 1 representation, in which case the ?: coding will be
superior.

Also, conditional execution (as found in the ARM) tends to render such jump
avoidance counter-productive, as there are unlikely to be any branches
involved in such a simple condition. The subtraction comes out as the
tedious:

intcmp
LDR a1,[a1]
LDR a2,[a2]
CMP a1,a2
MOVLE a1,#0
MOVGT a1,#1
MOVGE a2,#0
MOVLT a2,#1
SUB a1,a1,a2
MOV pc,lr

Whereas the ? : form wins by 1-4 cycles:

intcmp
LDR a1,[a1]
LDR a2,[a2]
CMP a1,a2
MVNLT a1,#0
MOVLT pc,lr
MOVLE a1,#0
MOVGT a1,#1
MOV pc,lr
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top