473,412 Members | 2,012 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,412 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 3855
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: 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...
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
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
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,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

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.