does it take cpu time to typecast?

T

Trishia Rose

this is something ive always wondered, does it take cpu time at run
time to typecast or just at compile time? for example consider the
two little bits of code:

int a = 5;
int b = a;

and:

char *a = (char*) 5;
int b = (int) a;

They both set b to the same thing (5), but does the 2nd one take more
cpu time at runtime?

I find that trick actually very useful in situations where you have a
rather long and often-edited (so that you dont want to copy and paste
a copy) utility function which is called in alot of places, one of
whose arguments is, say, an int, which is not necessarily used
(depending on another of its arguments, say, "int type"), and then
suddenly you realize it would be very useful to be able to pass a char
* to that utility function for some purpose while at the same time for
that same purpose you dont need to pass the int.
so for instance
void utility( int type, int argument )
{
switch( type )
{
case TYPE_HOUR:
printf( "The hour is currently %d.\n", argument ); break;
case TYPE_COUNT:
printf( "The count variable is currently %d.\n", argument ); break;
case TYPE_NAME:
printf( "The name variable is set to %s.\n", (char*) argument );
break;
}
}

Then you could do
utility( TYPE_HOUR, current_hour ); /* current_hour is an int */
utility( TYPE_COUNT, count ); /* count is an int */
utility( TYPE_NAME, (int) name ); /* name is a char pointer */

but the question is would this suck up tons of CPU time
unnecessarily...
 
I

Ivan Vecerina

Trishia Rose said:
this is something ive always wondered, does it take cpu time at run
time to typecast or just at compile time?

Casting typically has no runtime cost, but this
is platform-dependent.
void utility( int type, int argument )
{
switch( type )
{
case TYPE_HOUR:
printf( "The hour is currently %d.\n", argument ); break;
case TYPE_COUNT:
printf( "The count variable is currently %d.\n", argument ); break;
case TYPE_NAME:
printf( "The name variable is set to %s.\n", (char*) argument );
break;
}
} ....
but the question is would this suck up tons of CPU time
unnecessarily...

There is no reason to worry about CPU time here.
However, this code leads to undefined behavior, as
casting a pointer to an int and back is not portable.
For example, some 64-bit platforms have 64-bit
pointers but 32-bit integers...

Regards,
 
P

Programmer Dude

Trishia said:
this is something ive always wondered, does it take cpu time at run
time to typecast or just at compile time?

Depends on the cast and the platform. Casting a floating point
to an integer, or vice versa, probably requires an internal library
call. Casting one integer type to another may require nothing you
can see in the runtime binary. Casting one pointer type to
another *probably* requires nothing at all.

But, it depends.

If you're curious, write a short bit of code, have your compiler
emit the assembly (most can), and check it out. Here's an example
from one platform and compiler:

void Test (void)
{
short s;
long n;
float f;
double d;

s = 420;
n = (long) s;
f = (float) s;
d = (double) s;
printf ("SHORT: %d\n", (int)s);
printf ("Long: %ld\n", n);
printf ("Float: %f\n", (double)f);
printf ("Double: %f\n", d);

n = 420000L;
s = (short) n;
f = (float) n;
d = (double) n;
printf ("Short: %d\n", (int)s);
printf ("LONG: %ld\n", n);
printf ("Float: %f\n", (double)f);
printf ("Double: %f\n", d);

f = 4.2F;
s = (short) f;
n = (long) f;
d = (double) f;
printf ("Short: %d\n", (int)s);
printf ("Long: %ld\n", n);
printf ("FLOAT: %f\n", (double)f);
printf ("Double: %f\n", d);

d = 42.21;
s = (short) d;
n = (long) d;
f = (float) d;
printf ("Short: %d\n", (int)s);
printf ("Long: %ld\n", n);
printf ("Float: %f\n", (double)f);
printf ("DOUBLE: %f\n", d);
}

In my environment, the integer->integer casts don't do much.
The long->short just uses a short-sized register which truncates
the long. ALL the casts involving floating point types (including
float->double and vice versa) invoke the floating point parts of
the CPU. In this case there is some runtime penalty.
 
K

Kevin Easton

Trishia Rose said:
this is something ive always wondered, does it take cpu time at run
time to typecast or just at compile time? for example consider the
two little bits of code:

int a = 5;
int b = a;

and:

char *a = (char*) 5;
int b = (int) a;

They both set b to the same thing (5), but does the 2nd one take more
cpu time at runtime?

Actually, there's no guarantee that (int)(char *) 5 == 5. Everything
about pointer to integer casts is implementation-defined, so it's
impossible to say whether it can be done at compile-time or deferred
until runtime. The water is muddied in this particular instance by the
fact that a clever optimiser could see that it can compute both values
at compile-time, since nothing has a chance to change `a' between the
point it's initialised and where it's used to initialise `b'.

Any time a change of representation is required, the cast will not be
able to be done at runtime in all cases. For example:

int a;

scanf("%d", &a);
printf("%f", (double)a);

The conversion of an int to a double, which in all likelihood have
wildly different representations, clearly will take some CPU time.
I find that trick actually very useful in situations where you have a
rather long and often-edited (so that you dont want to copy and paste
a copy) utility function which is called in alot of places, one of
whose arguments is, say, an int, which is not necessarily used
(depending on another of its arguments, say, "int type"), and then
suddenly you realize it would be very useful to be able to pass a char
* to that utility function for some purpose while at the same time for
that same purpose you dont need to pass the int.
so for instance
void utility( int type, int argument )
{
switch( type )
{
case TYPE_HOUR:
printf( "The hour is currently %d.\n", argument ); break;
case TYPE_COUNT:
printf( "The count variable is currently %d.\n", argument ); break;
case TYPE_NAME:
printf( "The name variable is set to %s.\n", (char*) argument );
break;
}
}

Then you could do
utility( TYPE_HOUR, current_hour ); /* current_hour is an int */
utility( TYPE_COUNT, count ); /* count is an int */
utility( TYPE_NAME, (int) name ); /* name is a char pointer */

It's not guaranteed to work, because of the fact thta integer to pointer
conversions (and the inverse) are entirely implementation-defined.
There is a portable solution - this is what unions are for.

union int_or_string {
int i;
char *s;
};

void utility( int type, union int_or_string argument )
{
switch( type )
{
case TYPE_HOUR:
printf( "The hour is currently %d.\n", argument.i ); break;
case TYPE_COUNT:
printf( "The count variable is currently %d.\n", argument.i ); break;
case TYPE_NAME:
printf( "The name variable is set to %s.\n", (char*) argument.s );
break;
}

Because you're only allowed to read the last member written to in a
union, the intention is that they are stored in overlapping memory (so
the size of union int_or_string is the maximum of the size of an int and
a char *).

- Kevin.
 
E

E. Robert Tisdale

Trishia said:
This is something I've always wondered,
Does it take CPU time at run time to typecast or just at compile time?
For example, consider the two little bits of code:

int a = 5;
int b = a;

and:

char *a = (char*) 5;
int b = (int) a;

They both set b to the same thing (5),
but does the 2nd one take more CPU time at runtime?
> cat f0.c
int f(void) {
int a = 5;
return a;
}
> cat f1.c
int f(void) {
char* a = (char*)5;
return (int)a;
}
> gcc -Wall -std=c99 -pedantic -O2 -S f0.c
> gcc -Wall -std=c99 -pedantic -O2 -S f1.c
> diff f0.s f1.s
1c1
< .file "f0.c"
---
> .file "f1.c"

It makes no difference to my compiler, operating system
and machine architecture.
 
D

Dan Pop

In said:
Casting typically has no runtime cost, but this
is platform-dependent.

It is also cast-dependent. Casts perform data conversions. If the
representation of the result is different from the representation of the
operand, and if the value of the operand is not known at compile time, you
can bet that there is a run time cost. The typical example of non-free
casts is between integer and floating point data. Systems that don't use
two's complement also have to do some work when converting between signed
and unsigned types (if the signed data is negative, the representation
will change).

Dan
 
T

Trishia Rose

(e-mail address removed) (Trishia Rose) wrote in message news:<[email protected]>...
Consider:-
void hour_utility (int h);
void count_utility (int c);
void name_utility (const char *n);

The thing is, unlike most people I use linked lists (and hash tables)
extensively. And when using linked lists, sometimes it is desirable
to have a bunch of things in the same list which are the same
structure, but not truly the exact same entity. here is an example of
this structure:
struct pending_project
{
int type;
int percent;
void *data;
}

the type could be set to things like PROJECT_BUILDNEWOBJECT,
PROJECT_DESTROYOBJECT, PROJECT_CHANGEOBJECT, etc. Each of which would
require different data to be carried out, thus the pointer to the data
needed to carry out the project would be typecast'd to void and stuck
in this all-purpose "shell" thing, the advantage being that all
projects could then be shoved on the same queue. Otherwise one would
have to create tons of different queues, one for each of of the
project types. This would be tedious, RAM intensive, and would screw
up the whole first-in-first-out nature of a queue. And the tedium
would get exponentially worse for a hash table.
Anyway it also allows one to create generic project-handling
functions. For example say someone wants to see the status on a
project. Well that depends on the data, which is completely different
for different project types. It would be hugely tedious to program a
"show_project_status_(insert type here)" for each type, much better to
make a generic all-purpose one which uses a switch(type) and then some
typecasting to do it all in 1 function. Plus if you later want to
change, for instance, the aesthetic output of that show-status
function, it's way easier than if you made one for each type.
 
N

Nick Keighley

(e-mail address removed) (Nick Keighley) wrote in message


The thing is, unlike most people I use linked lists (and hash tables)
extensively. And when using linked lists, sometimes it is desirable
to have a bunch of things in the same list which are the same
structure, but not truly the exact same entity.

this is why C++ invented templates.

[...] here is an example of
this structure:
struct pending_project
{
int type;
int percent;
void *data;
}

the type could be set to things like PROJECT_BUILDNEWOBJECT,
PROJECT_DESTROYOBJECT, PROJECT_CHANGEOBJECT, etc. Each of which would
require different data to be carried out, thus the pointer to the data
needed to carry out the project would be typecast'd to void and stuck
in this all-purpose "shell" thing, the advantage being that all
projects could then be shoved on the same queue. Otherwise one would
have to create tons of different queues, one for each of of the
project types. This would be tedious, RAM intensive, and would screw
up the whole first-in-first-out nature of a queue. And the tedium
would get exponentially worse for a hash table.
Anyway it also allows one to create generic project-handling
functions. For example say someone wants to see the status on a
project. Well that depends on the data, which is completely different
for different project types. It would be hugely tedious to program a
"show_project_status_(insert type here)" for each type, much better to
make a generic all-purpose one which uses a switch(type) and then some
typecasting to do it all in 1 function. Plus if you later want to
change, for instance, the aesthetic output of that show-status
function, it's way easier than if you made one for each type.

yes. void* is the way (in C) to write generic queues etc. And you will
end up casting. Casting object (data) pointers to and from void* is ok
(as long as you cast back to the same type). This doesn't justify
trying to stuff char* into and int.

Your original question is "does this cost"? Casting between void*
and other object pointers usually won't cost much and often won't
cost anything.

Another possibility is to have a table of function pointers for
each type. This imitates C++'s v-table. It may involve you in too
much house-keeping to be worth while.


--
Nick Keighley

"The Real Programmer wants a "you asked for it, you got it"
text editor--complicated, cryptic, powerful, unforgiving,
dangerous. TECO, to be precise."
 
M

Malcolm

Trishia Rose said:
here is an example of
this structure:
struct pending_project
{
int type;
int percent;
void *data;
}
This is fine. A cast from void * to struct foo * will typically be free.
Even if it does cost a few instructions, unless the code is in an inner loop
it will make no noticaeable difference.
The thing you have to be wary of is casts from floating point to integer or
vice versa. These can soak up many CPU instructions. Again, it doesn't
matter unless you're in an inner loop.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top