472,989 Members | 3,016 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,989 software developers and data experts.

Safely casting pointer types, purpose of static_cast, etc.

There have been some recent threads about casting pointers to and from
void* that have me rethinking some of my usual practices. I have a
couple of questions.

1. What is the purpose of C++'s static_cast<>? In other words, is
there any real difference between statements like (with non-pointer
types):

double a = 3.4;
int b = (int)a; // <--- this
int c = static_cast<int>(a); // <---

2. What about static cast with void*'s and pointers to class types, is
there any difference here, and also, are these conversions all safe:

Object *a = new Object;
void *b = a;
Object *c = (Object *)b;
Object *d = static_cast<Object *>(b);

In that code is there any difference between the conversion when
initializing c and d? And, are c/d guaranteed to be valid pointers to
the same object a points to?

3. If c/d are not guaranteed to be valid pointers, what is the correct
way to do that conversion in a situation where a void* must be used as
an intermediate variable to hold a pointer to an object (e.g. when
passing through a layer of C code)? For example, when creating a
thread with pthread_create, a void* parameter can be passed to the
thread function. So, then, is the following code guaranteed to always
do what I want on any platform:

=== BEGIN EXAMPLE ===

class A {
public:
void CreateThread ();
private:
void * MyThreadProc_ ();
static void * SThreadProc_ (void *);
};

// creates a thread
void A::CreateThread () {
pthread_t tid;
// 4th param is void* param to pass to SThreadProc_.
pthread_create(&tid, NULL, &SThreadProc_, this);
}

// static thread function calls ((A*)va)->MyThreadProc_();
void * A::SThreadProc_ (void *va) {
A *a = (A *)va; // <--- is this always safe?
return a->MyThreadProc_();
}

=== END EXAMPLE ===

Thanks,

Jason
Jun 27 '08 #1
5 3813
There is not much difference but static casting is more
restrictive(safer) and noticeable.

On Jun 4, 4:21 pm, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.comwrote:
There have been some recent threads about casting pointers to and from
void* that have me rethinking some of my usual practices. I have a
couple of questions.

1. What is the purpose of C++'s static_cast<>? In other words, is
there any real difference between statements like (with non-pointer
types):

double a = 3.4;
int b = (int)a; // <--- this
int c = static_cast<int>(a); // <---

2. What about static cast with void*'s and pointers to class types, is
there any difference here, and also, are these conversions all safe:

Object *a = new Object;
void *b = a;
Object *c = (Object *)b;
Object *d = static_cast<Object *>(b);

In that code is there any difference between the conversion when
initializing c and d? And, are c/d guaranteed to be valid pointers to
the same object a points to?

3. If c/d are not guaranteed to be valid pointers, what is the correct
way to do that conversion in a situation where a void* must be used as
an intermediate variable to hold a pointer to an object (e.g. when
passing through a layer of C code)? For example, when creating a
thread with pthread_create, a void* parameter can be passed to the
thread function. So, then, is the following code guaranteed to always
do what I want on any platform:

=== BEGIN EXAMPLE ===

class A {
public:
void CreateThread ();
private:
void * MyThreadProc_ ();
static void * SThreadProc_ (void *);

};

// creates a thread
void A::CreateThread () {
pthread_t tid;
// 4th param is void* param to pass to SThreadProc_.
pthread_create(&tid, NULL, &SThreadProc_, this);

}

// static thread function calls ((A*)va)->MyThreadProc_();
void * A::SThreadProc_ (void *va) {
A *a = (A *)va; // <--- is this always safe?
return a->MyThreadProc_();

}

=== END EXAMPLE ===

Thanks,

Jason
Jun 27 '08 #2
In article <d5ce22d0-225b-42e4-8d6c-
c4**********@l42g2000hsc.googlegroups.com>, ja************@gmail.com
says...

[ ... ]
1. What is the purpose of C++'s static_cast<>? In other words, is
there any real difference between statements like (with non-pointer
types):

double a = 3.4;
int b = (int)a; // <--- this
int c = static_cast<int>(a); // <---
There is no difference between these statements. For that matter,

int c = 3.4;

is allowed, and does exactly the same thing as well.

The reason for static_cast over a C-style cast is mostly that it is more
restricted, and does NOT support some more dangerous conversions that C-
style casts can do. For example, a C-style cast can do roughly the same
thing as a const_cast, casting away const-ness, or it can do roughly the
same thing as a reinterpret_cast, treating a pointer as if it pointed to
a different type of operand.
2. What about static cast with void*'s and pointers to class types, is
there any difference here, and also, are these conversions all safe:

Object *a = new Object;
void *b = a;
Object *c = (Object *)b;
Object *d = static_cast<Object *>(b);

In that code is there any difference between the conversion when
initializing c and d? And, are c/d guaranteed to be valid pointers to
the same object a points to?
Yes, the conversions to c and d are the same. A C-style cast does the
same thing as a static_cast when/if a static_cast can do the conversion.
A static_cast can't do anything new that a C-style cast can't. The
advantage of a static_cast is solely that it is more restricted, so you
can't, for one example, accidentally cast away const-ness and/or
reinterpret what a pointer points at -- for example:

int const *a;
char *b = (char *)a; // perfectly legal
char *b = static_cast<char *>(a); // not allowed

The C-style cast is casting away the const-ness AND reintrepting what's
pointed at as a char instead of an int. A static_cast simply can't do
that -- if you really want to cast away const-ness, you need to use
const_cast. If you want to reinterpret what's pointed at, you have to
use reinterpret_cast. If you want to do both, you have to use both:

char *c = const_cast<char *>(reinterpret_cast<char const *>(a));

The C-style cast can do so many different kinds of conversions, with
nothing to distinguish between them, that it's easy to accidentally do a
conversion you don't want along with the one(s) you did. The new-style
casts attempt to prevent that.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #3
On Jun 5, 1:21 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.comwrote:
There have been some recent threads about casting pointers to
and from void* that have me rethinking some of my usual
practices. I have a couple of questions.
1. What is the purpose of C++'s static_cast<>?
To limit the types of casts which can be done. You can't
accidentally cast away const with it, for example. More
importantly, in a class hierarchy, a C style cast is a
static_cast if it is to a base or a derived, but a
reinterpret_cast (i.e. type punning) if it is to a sibling. (An
attempt to use static_cast in this case will cause compiler
error.) Also, static_cast (and dynamic_cast) respect the access
specifiers in an inheritance hierarchy; C style casts don't.
In other words, is there any real difference between
statements like (with non-pointer types):
Unless the types are pointers or references in an inheritance
hierarchy, there is not difference between a C style cast and a
static_cast, *if* the static_cast is legal. For non-pointer and
non-reference types, in fact, most code I've seen doesn't use
static_cast, but rather the function style casts, e.g.:
"MyClass( 43 )".
double a = 3.4;
int b = (int)a; // <--- this
int c = static_cast<int>(a); // <---
These two are totally indentical. Conceptually, I tend to think
of this as creating a new temporary object, rather than
accessing an existing object through a different type. In such
cases, I'll use a function style cast, or a C style cast with
the argument in parentheses, i.e. "int( a )" or "(int)( a )".
(The latter is necessary if the typename is not a single token,
e.g. "unsigned char".) In my mind, this is the syntax for
"creating a new, temporary object".

(Technically, a pointer cast also creates a new, temporary
object. But the new object is a pointer, and of course, for the
most part, when you use a pointer cast, you're concerned about
the access through the pointer.)
2. What about static cast with void*'s and pointers to class
types, is there any difference here, and also, are these
conversions all safe:
Object *a = new Object;
void *b = a;
Object *c = (Object *)b;
Object *d = static_cast<Object *>(b);
In that code is there any difference between the conversion
when initializing c and d? And, are c/d guaranteed to be valid
pointers to the same object a points to?
No difference, and yes. You can convert any pointer type to
void*, and convert it back *to* *the* *same* *type* without loss
of information. (Note that this more or less implies that void
pointers will be at least as large as any other pointer type.)
3. If c/d are not guaranteed to be valid pointers,
Irrelevant, because they are. I'd use static_cast in this case.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #4
On Jun 5, 1:21 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.comwrote:

[...]
3. If c/d are not guaranteed to be valid pointers,
As I said, they are guaranteed to be valid, but I missed some
important issues in your example.
what is the correct way to do that conversion in a situation
where a void* must be used as an intermediate variable to hold
a pointer to an object (e.g. when passing through a layer of C
code)? For example, when creating a thread with
pthread_create, a void* parameter can be passed to the thread
function. So, then, is the following code guaranteed to always
do what I want on any platform:
=== BEGIN EXAMPLE ===
class A {
public:
void CreateThread ();
private:
void * MyThreadProc_ ();
static void * SThreadProc_ (void *);
};
// creates a thread
void A::CreateThread () {
pthread_t tid;
// 4th param is void* param to pass to SThreadProc_.
pthread_create(&tid, NULL, &SThreadProc_, this);
}
// static thread function calls ((A*)va)->MyThreadProc_();
void * A::SThreadProc_ (void *va) {
A *a = (A *)va; // <--- is this always safe?
return a->MyThreadProc_();
}
=== END EXAMPLE ===
First, this won't compile with a compliant compiler. The type
of the third parameter to pthread_create is ``extern "C" void*
(*) (void*)'', and a member function, even static, can never
have a type with ``extern "C"''. You *must* use a free function
for this.

Secondly, as I said in my previous answer, the type you get from
the void* *must* be the same type as you used to create it.
That's not a problem here, but it very much could be if you
derive. A common mistaken idiom is something like:

class ThreadBase
{
public:
virtual ~ThreadBase() {}
virtual void run() = 0 ;
} ;

extern "C" void*
threadStarter( void* p )
{
static_cast< ThreadBase* >( p )->run() ;
return NULL ;
}

class MyThread : public ThreadBase
{
public:
virtual void run() ;
// ...
} ;

and then somewhere:

MyThread t ;
pthread_t ti ;
pthread_create( &ti, NULL, &threadStarter, &t ) ;

This does *not* work. Or rather, it is undefined behavior,
which may seem to work in some frequent cases. The last line
must be:

pthread_create( &ti, NULL, &threadStarter,
static_cast< ThreadBase* >( &t ) ) ;

for the behavior to be guaranteed---the cast from void* is to
ThreadBase*, so the void* must have been created from a
ThreadBase*, and not a MyThread*.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #5
Sorry, there's too much to quote, but thanks Jayesh, Jerry, James, for
the complete answers, and for keeping the non-J riff raff out as well.

- Jason
Jun 27 '08 #6

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

Similar topics

4
by: Jacob Jensen | last post by:
This question has probably been asked a million time, but here it comes again. I want to learn the difference between the three type cast operators: static_cast, reinterpret_cast, dynamic_cast. A...
16
by: He Shiming | last post by:
Hi, I'm having a little bit of trouble regarding pointer casting in my program. I don't understand why the following two cases produce different results. Case 1: IInterface *pInterface = new...
44
by: Agoston Bejo | last post by:
What happens exactly when I do the following: struct A { int i; string j; A() {} }; void f(A& a) { cout << a.i << endl;
33
by: Mark P | last post by:
A colleague asked me something along the lines of the following today. For some type X he has: X* px = new X; Then he wants to convert px to a char* (I'm guessing for the purpose of...
5
by: brekehan | last post by:
I've always been a little sketchy on the differences between static, dynamic, and reinterpret casting. I am looking to clean up the following block by using C++ casting instead of the C style...
9
by: Jess | last post by:
Hello, It seems both static_cast and dynamic_cast can cast a base class pointer/reference to a derived class pointer/reference. If so, is there any difference between them? In addition, if I...
7
by: Christopher Pisz | last post by:
My problem is my derived class is getting called twice instead of the base and then the derived. I thought this was the purpose for virtuals and dynamic casting :/ I want my base class to have its...
9
by: Taras_96 | last post by:
Hi everyone, I was experimenting with static_cast and reinterpret cast #include <iostream> struct A1 { int a; }; struct A2 { double d; }; struct B : public A1, A2
4
by: Wally Barnes | last post by:
Can someone help a poor C++ programmer that learned the language before there was a standard lib .. etc ? Basically I have two classes that look something like below: template <class T>...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
0
tracyyun
by: tracyyun | last post by:
Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
3
by: nia12 | last post by:
Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of...
4
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...
3
SueHopson
by: SueHopson | last post by:
Hi All, I'm trying to create a single code (run off a button that calls the Private Sub) for our parts list report that will allow the user to filter by either/both PartVendor and PartType. On...

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.