Does typecasting consume cpu cycles

V

Vinod Patel

I have a piece of code : -

void *data;
......
/* data initialized */
......
struct known_struct *var = (struct known_struct*) data; /*typecasting*/

How is this different from simple assignment.
int b = some_value;
int a = b; /* assignment */

Does above typecasting (struct known_struct*) need some extra cpu cycles???
or is it a simple assignment like 'a = b'.

Thanks for reply,
Vinod
 
D

Dave

Vinod said:
I have a piece of code : -

void *data;
.....
/* data initialized */
.....
struct known_struct *var = (struct known_struct*) data; /*typecasting*/

How is this different from simple assignment.
int b = some_value;
int a = b; /* assignment */

Does above typecasting (struct known_struct*) need some extra cpu cycles???
or is it a simple assignment like 'a = b'.

Thanks for reply,
Vinod


No.

The assignment itself may take some time (copying the pointer from one
memory location to another, or from one register to another, or the
compiler might optimise it out altogether), but that would be the
assignment, not the cast, taking the time.

The cast is there to tell the compiler "yes, that's really what I want
to do so STFU".

(It'll take some compiler time, of course, because the cast needs
parsing, but I presume you mean "does it consume runtime CPU cycles".)

Dave.
 
A

Alex Fraser

Vinod Patel said:
I have a piece of code : -

void *data;
.....
/* data initialized */
.....
struct known_struct *var = (struct known_struct*) data; /*typecasting*/

Conversion between pointer to void and other pointer types does not require
a cast.
How is this different from simple assignment.
int b = some_value;
int a = b; /* assignment */

The difference is simply that the types are different in the first case, so
a conversion is required. Just like there must be a conversion if b was
declared with type char above.
Does above typecasting (struct known_struct*) need some extra cpu
cycles??? or is it a simple assignment like 'a = b'.

It depends on the implementation. There is always a conversion irrespective
of the implementation, but that conversion may be a no-op (ie, may not
generate any code). This applies to many implementations, where all pointers
are the same size and use the same representation.

Alex
 
C

Chris Barts

Does above typecasting (struct known_struct*) need some extra cpu cycles???

If you have to know, most compilers have an option of printing assembly
opcodes into a file instead of just object code. Look at your compiler's
documentation.

On the other hand, don't bother. It's almost certainly not worth worrying
about. Tighten a loop or redesign some branches if you need to bum some
time out of your code.
 
I

Igmar Palsenberg

Dave said:
The cast is there to tell the compiler "yes, that's really what I want
to do so STFU".

It's 'convert x to y', not 'pretend x to be y'. Typecasts could require
extra instruction, but since this case is about pointers I cannot think
of a reason it should generate extra instructions.



Igmar
 
D

Dan Pop

In said:
I have a piece of code : -

void *data;
.....
/* data initialized */
.....
struct known_struct *var = (struct known_struct*) data; /*typecasting*/

How is this different from simple assignment.
int b = some_value;
int a = b; /* assignment */

Does above typecasting (struct known_struct*) need some extra cpu cycles???
or is it a simple assignment like 'a = b'.

It depends. If both pointer values have the same representation, it is as
simple as your assignment. OTOH, if a representation conversion is
necessary, it can be as complex as an assignment involving variables of
different types, as in:

double x = some_value;
int a = x;

Void pointers and structure pointers are not required to have the same
representation and if they don't, some extra CPU cycles may be needed.

The canonical example is one of the implementations for the Cray vector
processors, where the byte selector bits are stored in the least
significant bits of the pointer value. All pointers, except character and
void pointers are word pointers, i.e. they contain a word address. To
convert a void pointer to such a pointer, the compiler must shift it right
three bit positions and this doesn't happen by magic, actual machine
instructions are needed for that.

Another implementation for the same platform stores the byte selector
bits in the upper bits of the character/void pointers. In this case,
the conversion is a no-op: if the byte selector bits are not all zero,
the pointer was not correctly aligned for a word access and the program
invokes undefined behaviour, anyway. OTOH, character pointer arithmetic
is a lot more CPU expensive on this implementation, compared to the first
example, where plain unsigned integer arithmetic does the job.

This platform has native hardware support for word (64-bit) addressing
only (each address is the address of a word, not a byte) so,
implementations that don't want to store one character per word have to
deal with character (byte) addressing by adding a byte selector field to
the word pointers, in one of the ways described above. This three bit
field contains the address of the byte inside the word.

Dan
 
C

Chris Torek

Does above typecasting (struct known_struct*) need some extra cpu cycles???
or is it a simple assignment like 'a = b'.

In addition to the other replies, I think it is worth noting (yet
again) that a cast is just a source-code-syntax construct, consisting
of a type-name enclosed in parentheses. As such, one might as well
ask whether a longer variable name consumes more CPU cycles than
a shorter one. In general, source-specific items in C are gone by
the time you run a program -- they leave at most some trace of
themselves, so that their effects are indirect at best.

Thus, this question really needs to be redirected to whether a
*conversion* requires work at run-time. Casts are, of course,
explicit requests for conversions, but other conversions exist
as well. The absence of a cast does not mean there is *no*
conversion, and if there is already a conversion, adding a cast
may have no effect at all, or may simply change the effect from
"convert type W to type X" into "convert type W to type Y".

As others noted, whether a conversion involved in some assignment
requires more time than an assignment that is conversion-free is
quite machine-dependent. A surprising number of conversions require
no instructions, or at least no extra instructions; and on a useful
number of modern CPUs, even those that require extra instructions
may in fact take no extra time.

Because of all of this, the rule C programmers should use is: write
your code to be as readable and maintainable as you possibly can.
(This often means making it as portable as possible as well, since
portability tends to increase maintainability.) Then, once the
code works correctly, if it is too slow, profile it to find out
where it is slow; address slowness with algorithmic optimizations
first; and resort to "micro-optimization" only in emergencies.
 
V

Vinod Patel

I have got two cases: -
CASE 1
void *data;
struct known_struct *var = data;
printf("%d", var->first_int);

CASE 2
void *data;
printf("%d", (struct known_struct*) data->first_int);

In case 1, we use a variable named 'var' to point to 'data'. And then
we access an integer named 'first_int' in the data pointed by var.
So, count a memory overhead (creating 'var' on stack), second is
assignment overhead (var = data).

In case 2, we have not used any extra variable.
We typecast 'data' into (struct known_struct*) and then access its
'first_int'.
So, this seems to me as no memory overhead and no assignment overhead.
So is there any extra hidden overhead due to this typecasting.

Thanx for replies,
Vinod
 
A

Alex Fraser

Vinod Patel said:
I have got two cases: -
CASE 1
void *data;
struct known_struct *var = data;
printf("%d", var->first_int);

CASE 2
void *data;
printf("%d", (struct known_struct*) data->first_int);

In case 1, we use a variable named 'var' to point to 'data'. And then
we access an integer named 'first_int' in the data pointed by var.
So, count a memory overhead (creating 'var' on stack), second is
assignment overhead (var = data).

And conversion overhead (which may be zero).
In case 2, we have not used any extra variable.
We typecast 'data' into (struct known_struct*) and then access its
'first_int'.
So, this seems to me as no memory overhead and no assignment overhead.
So is there any extra hidden overhead due to this typecasting.

The cast causes the same conversion as happens before the assignment to var
above.

A good compiler will probably generate identical code in both of your cases.
Even if it does not, the difference will be (a) due to the assignment rather
than the conversion (the latter happens in both cases), and (b) probably
very, very small anyway. Do whatever makes the code easier to read, which I
suggest is case 1.

Alex
 
F

Flash Gordon

On 14 Sep 2004 23:44:09 -0700
(e-mail address removed) (Vinod Patel) wrote:

I have got two cases: -
CASE 1
void *data;
struct known_struct *var = data;
printf("%d", var->first_int);

CASE 2
void *data;
printf("%d", (struct known_struct*) data->first_int);

In case 1, we use a variable named 'var' to point to 'data'. And then
we access an integer named 'first_int' in the data pointed by var.
So, count a memory overhead (creating 'var' on stack), second is
assignment overhead (var = data).

In case 2, we have not used any extra variable.
We typecast 'data' into (struct known_struct*) and then access its
'first_int'.
So, this seems to me as no memory overhead and no assignment overhead.
So is there any extra hidden overhead due to this typecasting.

It depends ENTIRELY on your implementation and the switches you use when
you invoke it. In case 1 is might not bother allocating space for var
(unless something else forces it to, like you taking it's address) and
in case 2 it might decide to store the pointer in RAM after the
conversion.

You will have to either ask on a group dedicated to your implementation
or try it and see since the C standard does not specify how efficient
the compiled code has to be.
 
C

Chris Torek

I have got two cases: -
CASE 1
void *data;
struct known_struct *var = data;
printf("%d", var->first_int);

CASE 2
void *data;
printf("%d", (struct known_struct*) data->first_int);

This second version is wrong -- the "->" operator binds more
tightly than the cast operator, so this must be written with
parentheses:

printf("%d", ((struct known_struct *)data)->first_int);
In case 1, we use a variable named 'var' to point to 'data'. And then
we access an integer named 'first_int' in the data pointed by var.
So, count a memory overhead (creating 'var' on stack), second is
assignment overhead (var = data).

In case 2, we have not used any extra variable.
We typecast 'data' into (struct known_struct*) and then access its
'first_int'.
So, this seems to me as no memory overhead and no assignment overhead.
So is there any extra hidden overhead due to this typecasting.

A cast (the syntax with the type name in parentheses) is, semantically
and essentially, just an assignment to a temporary variable whose
type is given by the cast. Thus, case 2 has an extra temporary
variable and assignment, just like case 1. For more, I refer you
to my longer answer from yesterday, but now that we have actual
sample code to test, let us find out which version generates which
instruction(s) using GCC on the Intel x86 platform:

% cat t.c
struct known_struct { int first_int; int second_int; };

int f1(void *data) {
struct known_struct *var = data;
return var->first_int;
}

int f2(void *data) {
return ((struct known_struct *)data)->first_int;
}
% cc -O2 -S -mregparm=3 -fomit-frame-pointer t.c
[The -mregparm and -fomit-frame-pointer generate smaller/faster
code, at the expense of some ABI compatibility and debug-ability;
I used this to eliminate the usual frame and stack access to
make the generated assembly code more obvious.]
% cat t.s
[edited to toss irrelevant junk]
f1:
movl (%eax),%eax
ret

f2:
movl (%eax),%eax
ret

Functions f1() and f2() produced identical code, consisting of a
single "movl" instruction with identical operands (plus of course
the required "ret"urn instruction). Which instruction do you think
is faster -- movl, or movl? :)
 
V

Vinod Patel

Chris Torek said:
I have got two cases: -
CASE 1
void *data;
struct known_struct *var = data;
printf("%d", var->first_int);

CASE 2
void *data;
printf("%d", (struct known_struct*) data->first_int);

This second version is wrong -- the "->" operator binds more
tightly than the cast operator, so this must be written with
parentheses:

printf("%d", ((struct known_struct *)data)->first_int);
In case 1, we use a variable named 'var' to point to 'data'. And then
we access an integer named 'first_int' in the data pointed by var.
So, count a memory overhead (creating 'var' on stack), second is
assignment overhead (var = data).

In case 2, we have not used any extra variable.
We typecast 'data' into (struct known_struct*) and then access its
'first_int'.
So, this seems to me as no memory overhead and no assignment overhead.
So is there any extra hidden overhead due to this typecasting.

A cast (the syntax with the type name in parentheses) is, semantically
and essentially, just an assignment to a temporary variable whose
type is given by the cast. Thus, case 2 has an extra temporary
variable and assignment, just like case 1. For more, I refer you
to my longer answer from yesterday, but now that we have actual
sample code to test, let us find out which version generates which
instruction(s) using GCC on the Intel x86 platform:

% cat t.c
struct known_struct { int first_int; int second_int; };

int f1(void *data) {
struct known_struct *var = data;
return var->first_int;
}

int f2(void *data) {
return ((struct known_struct *)data)->first_int;
}
% cc -O2 -S -mregparm=3 -fomit-frame-pointer t.c
[The -mregparm and -fomit-frame-pointer generate smaller/faster
code, at the expense of some ABI compatibility and debug-ability;
I used this to eliminate the usual frame and stack access to
make the generated assembly code more obvious.]
% cat t.s
[edited to toss irrelevant junk]
f1:
movl (%eax),%eax
ret

f2:
movl (%eax),%eax
ret

Functions f1() and f2() produced identical code, consisting of a
single "movl" instruction with identical operands (plus of course
the required "ret"urn instruction). Which instruction do you think
is faster -- movl, or movl? :)

Greetings to the C-Gurus, thanks for all the replies.
Special thanks to Chris Torek, for giving a detailed explanation. The
sample test program really helped.

Rgds,
Vinod
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top