I know it is an integer type that can be cast to/from pointer without loss of data, but why would I ever want to do this? What advantage does having an integer type have over void* for holding the pointer and THE_REAL_TYPE* for pointer arithmetic?
EDIT
The question marked as "already been asked" doesn't answer this. The question there is if using intptr_t as a general replacement for void* is a good idea, and the answers there seem to be "don't use intptr_t", so my question is still valid: What would be a good use case for intptr_t?
The primary reason, you cannot do bitwise operation on a void *, but you can do the same on a intptr_t.
On many occassion, where you need to perform bitwise operation on an address, you can use intptr_t.
However, for bitwise operations, best approach is to use the unsigned counterpart, uintptr_t.
As mentioned in the other answer by #chux, pointer comparison is another important aspect.
Also, FWIW, as per C11 standard, §7.20.1.4,
These types are optional.
There's also a semantic consideration.
A void* is supposed to point to something. Despite modern practicality, a pointer is not a memory address. Okay, it usually/probably/always(!) holds one, but it's not a number. It's a pointer. It refers to a thing.
A intptr_t does not. It's an integer value, that is safe to convert to/from a pointer so you can use it for antique APIs, packing it into a pthread function argument, things like that.
That's why you can do more numbery and bitty things on an intptr_t than you can on a void*, and why you should be self-documenting by using the proper type for the job.
Ultimately, almost everything could be an integer (remember, your computer works on numbers!). Pointers could have been integers. But they're not. They're pointers, because they are meant for different use. And, theoretically, they could be something other than numbers.
The uintptr_t type is very useful when writing memory management code. That kind of code wants to talk to its clients in terms of generic pointers (void *), but internally do all kinds of arithmetic on addresses.
You can do some of the same things by operating in terms of char *, but not everything, and the result looks like pre-Ansi C.
Not all memory management code uses uintptr_t - as an example, the BSD kernel code defines a vm_offset_t with similar properties. But if you are writing e.g. a debug malloc package, why invent your own type?
It's also helpful when you have %p available in your printf, and are writing code that needs to print pointer sized integral variables in hex on a variety of architectures.
I find intptr_t rather less useful, except possibly as a way station when casting, to avoid the dread warning about changing signedness and integer size in the same cast. (Writing portable code that passes -Wall -Werror on all relevant architectures can be a bit of a struggle.)
What is the use of intptr_t?
Example use: order comparing.
Comparing pointers for equality is not a problem.
Other compare operations like >, <= may be UB. C11dr §6.5.8/5 Relational operators.
So convert to intptr_t first.
[Edit] New example: Sort an array of pointers by pointer value.
int ptr_cmp(const void *a, const void *b) {
intptr_t ia = (intptr) (*((void **) a));
intptr_t ib = (intptr) (*((void **) b));
return (ia > ib) - (ia < ib);
}
void *a[N];
...
qsort(a, sizeof a/sizeof a[0], sizeof a[0], ptr_cmp);
[Former example]
Example use: Test if a pointer is of an array of pointers.
#define N 10
char special[N][1];
// UB as testing order of pointer, not of the same array, is UB.
int test_special1(char *candidate) {
return (candidate >= special[0]) && (candidate <= special[N-1]);
}
// OK - integer compare
int test_special2(char *candidate) {
intptr_t ca = (intptr_t) candidate;
intptr_t mn = (intptr_t) special[0];
intptr_t mx = (intptr_t) special[N-1];
return (ca >= mn) && (ca <= mx);
}
As commented by #M.M, the above code may not work as intended. But at least it is not UB. - just non-portably functionality. I was hoping to use this to solve this problem.
(u)intptr_t is used when you want to do arithmetic on pointers, specifically bitwise operations. But as others said, you'll almost always want to use uintptr_t because bitwise operations are better done in unsigned. However if you need to do an arithmetic right shift then you must use intptr_t1. It's usually used for storing data in the pointer, usually called tagged pointer
In x86-64 you can use the high 16/7 bits of the address for data, but you must do sign extension manually to make the pointer canonical because it doesn't have a flag for ignoring the high bits like in ARM2. So for example if you have char* tagged_address then you'll need to do this before dereferencing it
char* pointer = (char*)((intptr_t)tagged_address << 16 >> 16);
The 32-bit Chrome V8 engine uses smi (small integer) optimization where the low bits denote the type
|----- 32 bits -----|
Pointer: |_____address_____w1| # Address to object, w = weak pointer
Smi: |___int31_value____0| # Small integer
So when the pointer's least significant bit is 0 then it'll be right shifted to retrieve the original 31-bit signed int
int v = (intptr_t)address >> 1;
For more information read
Using the extra 16 bits in 64-bit pointers
Pointer magic for efficient dynamic value representations
Another usage is when you pass a signed integer as void* which is usually done in simple callback functions or threads
void* my_thread(void *arg)
{
intptr_t val = (intptr_t)arg;
// Do something
}
int main()
{
pthread_t thread1;
intptr_t some_val = -2;
int r = pthread_create(&thread1, NULL, my_thread, (void*)some_val);
}
1 When the implementation does arithmetic shift on signed types of course
2 Very new x86-64 CPUs may have UAI/LAM support for that
Related
In the following example the value-representation of an uint32_t is copied to an uint8_t array. This is done by std::memcpy. As I understand the C++ standard this is totally legal: we are accessing an object of type T via T* casted to a unsigned char*. No aliasing problem, no alignment problem.
The other way round is less obvious. We are accessing the object representation of T via unsigned char*, which is legal. But does the term accessing include changing?
Of course there are no aliasing and no aligment problems. There are however problems if the values in buffer s origin from a foreign source: we must ensure the right endianness and omit trap representations. The right endianness can be checked, so that can be solved.
But what about trap representations? How can we avoid that? Or do uint-types not have trap representations as opposed to say double?
I know that another (more compliant?) way would be shifting the uint8_t values into the uint_t object. We still have to obey the endianness but this should safely omit trap representations.
But shifts of large types on small µC (8-Bit) can be quite expensive!
The next question is if the second try (see below in the code) is equivalent to the memcpy approach with respect to legality and functionality? Well, it looks like the memcpy version is more optimizer friendly.
#include <cstdint>
#include <cstring>
#include <cassert>
typedef uint32_t utype;
constexpr utype value = 0x01020304;
int main() {
utype a{value};
utype b{0};
uint8_t s[sizeof(utype)]{};
// first
std::memcpy(s, &a, sizeof(utype));
assert(s[0] == (value & 0xff));
std::memcpy(&b, s, sizeof(utype));
assert(b == value);
// second
const uint8_t* ap = reinterpret_cast<const uint8_t*>(&a);
s[0] = ap[0]; // explicitly legal in C++
s[1] = ap[1];
s[2] = ap[2];
s[3] = ap[3];
assert(s[0] == (value & 0xff));
uint8_t* bp = reinterpret_cast<uint8_t*>(&b);
bp[0] = s[0]; // same as memcpy or ist this UB ?
bp[1] = s[1];
bp[2] = s[2];
bp[3] = s[3];
assert(b == value);
}
But does the term accessing include changing?
Yes.
Note: In fact that's what memcpy does conceptionally. It modifies bytes as if they were narrow character objects.
If this weren't possible, then memcpy couldn't be implemented in standard c++.
But what about trap representations? How can we avoid that?
This is quite tricky. If you know of a trap representation, then you would have to test for it using the narrow character view of the object, before trying to use the value in the type that has a trap representation. I don't know if there are any standard ways of dealing with trap representations.
Maybe there should be a std::is_trap<T>(void*) trait to solve this, but there isn't as far as I know.
I know that another (more compliant?) way would be shifting the uint8_t values into the uint_t object. We still have to obey the endianness but this should safely omit trap representations.
If the foreign value is a trap representation, then that value probably isn't representable anyway, so this shifting might have some other problem such as overflow in such case.
The difference between shifting and memcpy is that shifting allows converting known endianness to native endianness while memcpy works when the source already has native endianness.
If it were guaranteed that uint8_t were an alias of unsigned char, then the second snippet would be well defined and functionally equivalent to memcpy. I don't know if it is guaranteed, but it is certainly common. Only narrow character type has exceptions to pointer aliasing rules.
assert(s[0] == (value & 0xff));
This assert relies on endianness of the cpu.
I have a function with prototype void* myFcn(void* arg) which is used as the starting point for a pthread. I need to convert the argument to an int for later use:
int x = (int)arg;
The compiler (GCC version 4.2.4) returns the error:
file.cpp:233: error: cast from 'void*' to 'int' loses precision
What is the proper way to cast this?
You can cast it to an intptr_t type. It's an int type guaranteed to be big enough to contain a pointer. Use #include <cstdint> to define it.
Again, all of the answers above missed the point badly. The OP wanted to convert a pointer value to a int value, instead, most the answers, one way or the other, tried to wrongly convert the content of arg points to to a int value. And, most of these will not even work on gcc4.
The correct answer is, if one does not mind losing data precision,
int x = *((int*)(&arg));
This works on GCC4.
The best way is, if one can, do not do such casting, instead, if the same memory address has to be shared for pointer and int (e.g. for saving RAM), use union, and make sure, if the mem address is treated as an int only if you know it was last set as an int.
Instead of:
int x = (int)arg;
use:
int x = (long)arg;
On most platforms pointers and longs are the same size, but ints and pointers often are not the same size on 64bit platforms. If you convert (void*) to (long) no precision is lost, then by assigning the (long) to an (int), it properly truncates the number to fit.
There's no proper way to cast this to int in general case. C99 standard library provides intptr_t and uintptr_t typedefs, which are supposed to be used whenever the need to perform such a cast comes about. If your standard library (even if it is not C99) happens to provide these types - use them. If not, check the pointer size on your platform, define these typedefs accordingly yourself and use them.
Casting a pointer to void* and back is valid use of reinterpret_cast<>. So you could do this:
pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*
Then in myFcn:
void* myFcn(void* arg)
{
int* data = reinterpret_cast<int*>(arg);
int x = *data;
delete data;
Note: As sbi points out this would require a change on the OP call to create the thread.
What I am trying to emphasis that conversion from int to pointer and back again can be frough with problems as you move from platform to platform. BUT converting a pointer to void* and back again is well supported (everywhere).
Thus as a result it may be less error prone to generate a pointer dynamcially and use that.
Remembering to delete the pointer after use so that we don't leak.
Instead of using a long cast, you should cast to size_t.
int val= (int)((size_t)arg);
The proper way is to cast it to another pointer type. Converting a void* to an int is non-portable way that may work or may not! If you need to keep the returned address, just keep it as void*.
Safest way :
static_cast<int>(reinterpret_cast<long>(void * your_variable));
long guarantees a pointer size on Linux on any machine. Windows has 32 bit long only on 64 bit as well. Therefore, you need to change it to long long instead of long in windows for 64 bits.
So reinterpret_cast has casted it to long type and then static_cast safely casts long to int, if you are ready do truncte the data.
There is no "correct" way to store a 64-bit pointer in an 32-bit integer. The problem is not with casting, but with the target type loosing half of the pointer. The 32 remaining bits stored inside int are insufficient to reconstruct a pointer to the thread function. Most answers just try to extract 32 useless bits out of the argument.
As Ferruccio said, int must be replaced with intptr_t to make the program meaningful.
If you call your thread creation function like this
pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));
then the void* arriving inside of myFcn has the value of the int you put into it. So you know you can cast it back like this
int myData = reinterpret_cast<int>(arg);
even though the compiler doesn't know you only ever pass myFcn to pthread_create in conjunction with an integer.
Edit:
As was pointed out by Martin, this presumes that sizeof(void*)>=sizeof(int). If your code has the chance to ever be ported to some platform where this doesn't hold, this won't work.
I would create a structure and pass that as void* to pthread_create
struct threadArg {
int intData;
long longData;
etc...
};
threadArg thrArg;
thrArg.intData = 4;
...
pthread_create(&thread, NULL, myFcn, (void*)(threadArg*)&thrArg);
void* myFcn(void* arg)
{
threadArg* pThrArg = (threadArg*)arg;
int computeSomething = pThrArg->intData;
...
}
Keep in mind that thrArg should exist till the myFcn() uses it.
What you may want is
int x = reinterpret_cast<int>(arg);
This allows you to reinterpret the void * as an int.
//new_fd is a int
pthread_create(&threads[threads_in_use] , NULL, accept_request, (void*)((long)new_fd));
//inside the method I then have
int client;
client = (long)new_fd;
Hope this helps
Don't pass your int as a void*, pass a int* to your int, so you can cast the void* to an int* and copy the dereferenced pointer to your int.
int x = *static_cast<int*>(arg);
In my case, I was using a 32-bit value that needed to be passed to an OpenGL function as a void * representing an offset into a buffer.
You cannot just cast the 32-bit variable to a pointer, because that pointer on a 64-bit machine is twice as long. Half your pointer will be garbage. You need to pass an actual pointer.
This will get you a pointer from a 32 bit offset:
int32 nOffset = 762; // random offset
char * pOffset = NULL; // pointer to hold offset
pOffset += nOffset; // this will now hold the value of 762 correctly
glVertexAttribPointer(binding, nStep, glType, glTrueFalse, VertSize(), pOffset);
A function pointer is incompatible to void* (and any other non function pointer)
Well it does this because you are converting a 64 bits pointer to an 32 bits integer so you loose information.
You can use a 64 bits integer instead howerver I usually use a function with the right prototype and I cast the function type :
eg.
void thread_func(int arg){
...
}
and I create the thread like this :
pthread_create(&tid, NULL, (void*(*)(void*))thread_func, (void*)arg);
I want to split large variables like floats into byte segments and send these serially byte by byte via UART. I'm using C/C++.
One method could be to deepcopy the value I want to send to a union and then send it. I think that would be 100% safe but slow. The union would look like this:
union mySendUnion
{
mySendType sendVal;
char[sizeof(mySendType)] sendArray;
}
Another option could be to cast the pointer to the value I want to send, into a pointer to a particular union. Is this still safe?
The third option could be to cast the pointer to the value I want to send to a char, and then increment a pointer like this:
sendType myValue = 443.2;
char* sendChar = (char*)myValue;
for(char i=0; i< sizeof(sendType) ; i++)
{
Serial.write(*(sendChar+j), 1);
}
I've had succes with the above pointer arithmetics, but I'm not sure if it's safe under all circumstances. My concern is, what if we for instance is using a 32 bit processor and want to send a float. The compiler choose to store this 32 bit float into one memory cell, but does only store one single char into each 32 bit cell.
Each counter increment would then make the program pointer increment one whole memory cell, and we would miss the float.
Is there something in the C standard that prevents this, or could this be an issue with a certain compiler?
First off, you can't write your code in "C/C++". There's no such language as "C/C++", as they are fundamentally different languages. As such, the answer regarding unions differs radically.
As to the title:
Are casts as safe as unions?
No, generally they aren't, because of the strict aliasing rule. That is, if you type-pun a pointer of one certain type with a pointer to an incompatible type, it will result in undefined behavior. The only exception to this rule is when you read or manipulate the byte-wise representation of an object by aliasing it through a pointer to (signed or unsigned) char. As in your case.
Unions, however, are quite different bastards. Type punning via copying to and reading from unions is permitted in C99 and later, but results in undefined behavior in C89 and all versions of C++.
In one direction, you can also safely type pun (in C99 and later) using a pointer to union, if you have the original union as an actual object. Like this:
union p {
char c[sizeof(float)];
float f;
} pun;
union p *punPtr = &pun;
punPtr->f = 3.14;
send_bytes(punPtr->c, sizeof(float));
Because "a pointer to a union points to all of its members and vice versa" (C99, I don't remember the exact pargraph, it's around 6.2.5, IIRC). This isn't true in the other direction, though:
float f = 3.14;
union p *punPtr = &f;
send_bytes(punPtr->c, sizeof(float)); // triggers UB!
To sum up: the following code snippet is valid in both C89, C99, C11 and C++:
float f = 3.14;
char *p = (char *)&f;
size_t i;
for (i = 0; i < sizeof f; i++) {
send_byte(p[i]); // hypotetical function
}
The following is only valid in C99 and later:
union {
char c[sizeof(float)];
float f;
} pun;
pun.f = 3.14;
send_bytes(pun.c, sizeof float); // another hypotetical function
The following, however, would not be valid:
float f = 3.14;
unsigned *u = (unsigned *)&f;
printf("%u\n", *u); // undefined behavior triggered!
Another solution that is always guaranteed to work is memcpy(). The memcpy() function does a bytewise copying between two objects. (Don't get me started on it being "slow" -- in most modern compilers and stdlib implementations, it's an intrinsic function).
A general advice when sending floating point data on a byte stream would be to use some serialization technology, to ensure that the data format is well defined (and preferably architecture neutral, beware of endianness issues!).
You could use XDR -or perhaps ASN1- which is a binary format (see xdr(3) for more). For C++, see also libs11n
Unless speed or data size is very critical, I would suggest instead a textual format like JSON or perhaps YAML (textual formats are more verbose, but easier to debug and to document). There are several good libraries supporting it (e.g. jsoncpp for C++ or jansson for C).
Notice that serial ports are quite slow (w.r.t. CPU). So the serialization processing time is negligible.
Whatever you do, please document the serialization format (even for an internal project).
The cast to [[un]signed] char [const] * is legal and it won't cause issues when reading, so that is a fine option (that is, after fixing char *sendChar = reinterpret_cast<char*>(&myValue);, and since you are at it, make it const)
Now the next problem comes on the other side, when reading, as you cannot safely use the same approach for reading. In general, the cost of copying the variables is much less than the cost of sending over the UART, so I would just use the union when reading out of the serial.
I know this is a rather noobish question, but no amount of googling or permutations of code seem to work.
I have a structure which is defined like this.
typedef struct
{
int rate;
int duration;
} DummyStructure;
Now, i try to use code similar to this.
//
DummyStructure* structure;
DummyStructure* structure2;
long int point;
//
structure = (DummyStructure*)malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = (long int)&structure;
// now i'd like to set structure2 to the same memory location as 1.
// point is the 8-byte int location (i assume?) of structure.
// so naturally i'd assume that by casting as a DummyStructure pointer
// that long int would act as a pointer to that 1.
// It doesn't.
structure2 = (DummyStructure*)point;
I stress that i've tried every permutation of ** and * that is possible. I just don't get it. Either it doesn't compile, or it does, and when it does i end up with seemingly random numbers for the fields contained in structure2. I assume that somehow i'm winding up with an incorrect memory location, but how else can you get it except from using the &?
I have the memory location, right? How do i set the structure to that location?
EDIT; I forgot to mention (and subsequent answers have asked) but i'm intending to use this to wrap libvorbis for jni. Using jni means that i can't pass-back any of the structs that libvorbis does, but it requires them for its core functions. Therefore my wrapper is going to use vorbis directly to make the structs, and i pass back to java the pointer to them so that when i need to fill the buffer with more sound, i can simply re-reference the struct objects from the integer value of the pointer.
Why are you trying to cast pointers to integers and back? Is it just to learn, to figure something out, to work around some (untold) restriction, or what? It's a rather strange thing to be doing in a "plain" program such as this, as there is no point.
One likely cause of your problems is that there's no guarantee that a pointer will even fit in a long int. You can check by adding this code:
printf("a regular pointer is %u bytes, long int is %u",
(unsigned int) sizeof structure, (unsigned int) sizeof point);
If the numbers printed are different, that's probably the largest cause of your problems.
If you're using C99, you should #include <stdint.h> and then use the intptr_t type instead of unsigned long to hold a pointer, in any case.
structure is already a pointer, so you don't have to take the address there:
long int point = reinterpret_cast<long int>(structure);
DummyStructure* structure2 = reinterpret_cast<DummyStructure*>(point);
structure is already a pointer. You just want to do point = (long int) structure; (although, realistically, why a long int is involved at all, I don't know. It's a lot easier to just do structure2=structure; which works fine since structure and structure2 are both pointers.)
When you do &structure you're getting the memory location where the pointer itself is stored, which is why it isn't the correct value. You really probably don't want to ever use &structure unless it's being passed into a function which is going to change which DummyStructure structure points to.
Others have answered your question, but I'd like to make a more general comment. You mention JNI; in this case, you don't want long int, but jlong (which will be a typedef to either long int or long long int, depending on the machine. The problem is that long will have a different size, depending on the machine, and will map to a different Java type. Of course, you're counting on the fact that jlong will be big enough to hold a pointer, but since jlong is 64 bits, this seems like a safe bet for the immediate future (and beyond—I don't see a time coming where 64 bits of addressing doesn't suffice).
Also, I would suggest you borrow an idea from Swig, and avoid the subtleties of pointer to integral conversions, by using something like the following:
jlong forJNI = 0;
*reinterpret_cast<DummyStructure*>( &forJNI ) = structure;
// ...
structure2 = *reinterpret_cast<DummyStructure*>( &forJNI );
This is ugly, but it is guaranteed to work (with one caveat) for all
systems where sizeof(DummyStructure*) <= 64.
Just be sure to compile with strict aliasing turned off. (You have to
do this anytime you cast between pointers and ints. IMHO, you shouldn't
have to in cases where the casts are visible to the compiler, but some
compiler writers prefer breaking code intentionally, even when the
intent is clear.)
Long ints aren't the same as pointers. Why don't you just do:
DummyStructure** point;
structure = malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = &structure;
structure2 = *point;
The problem is probably a combination of the fact that 1) you don't dereference point. structure2 is a pointer to structure which is itself a pointer. You'd have to do:
structure2 = *((DummyStructure*)point);
But on top of that is the fact that long ints aren't the same as pointers. There's probably also a signedness issue here.
point = (long int)&structure;
This takes the address of structure which is a DummyStructure* and assign it to point. So point should be a double pointer (pointer to pointer). And when you assign structure2, it should be properly type casted.
typedef struct
{
int rate;
int duration;
} DummyStructure;
DummyStructure* structure;
DummyStructure* structure2;
long int **point;
structure = (DummyStructure*)malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = (long int **)&structure;
structure2 = (DummyStructure*)*point;
If your intention is to make structure2 point to the same memory location as structure, why don't you directly assign it rather than having an intermediate long int **.
The bug is that point is the address of structure, which is itself a pointer to a DummyStructure. In order for structure2 to point to the same thing as structure, you need to dereference point. Ignoring for a second all length, signedness, and similar issues,
structure2 = *(DummyStructure**)point;
would fix your code. But why not just:
structure2 = structure;
If you really want to hold a pointer in something generic, hold it in a void*. At least that's the right size.
I have a function with prototype void* myFcn(void* arg) which is used as the starting point for a pthread. I need to convert the argument to an int for later use:
int x = (int)arg;
The compiler (GCC version 4.2.4) returns the error:
file.cpp:233: error: cast from 'void*' to 'int' loses precision
What is the proper way to cast this?
You can cast it to an intptr_t type. It's an int type guaranteed to be big enough to contain a pointer. Use #include <cstdint> to define it.
Again, all of the answers above missed the point badly. The OP wanted to convert a pointer value to a int value, instead, most the answers, one way or the other, tried to wrongly convert the content of arg points to to a int value. And, most of these will not even work on gcc4.
The correct answer is, if one does not mind losing data precision,
int x = *((int*)(&arg));
This works on GCC4.
The best way is, if one can, do not do such casting, instead, if the same memory address has to be shared for pointer and int (e.g. for saving RAM), use union, and make sure, if the mem address is treated as an int only if you know it was last set as an int.
Instead of:
int x = (int)arg;
use:
int x = (long)arg;
On most platforms pointers and longs are the same size, but ints and pointers often are not the same size on 64bit platforms. If you convert (void*) to (long) no precision is lost, then by assigning the (long) to an (int), it properly truncates the number to fit.
There's no proper way to cast this to int in general case. C99 standard library provides intptr_t and uintptr_t typedefs, which are supposed to be used whenever the need to perform such a cast comes about. If your standard library (even if it is not C99) happens to provide these types - use them. If not, check the pointer size on your platform, define these typedefs accordingly yourself and use them.
Casting a pointer to void* and back is valid use of reinterpret_cast<>. So you could do this:
pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*
Then in myFcn:
void* myFcn(void* arg)
{
int* data = reinterpret_cast<int*>(arg);
int x = *data;
delete data;
Note: As sbi points out this would require a change on the OP call to create the thread.
What I am trying to emphasis that conversion from int to pointer and back again can be frough with problems as you move from platform to platform. BUT converting a pointer to void* and back again is well supported (everywhere).
Thus as a result it may be less error prone to generate a pointer dynamcially and use that.
Remembering to delete the pointer after use so that we don't leak.
Instead of using a long cast, you should cast to size_t.
int val= (int)((size_t)arg);
The proper way is to cast it to another pointer type. Converting a void* to an int is non-portable way that may work or may not! If you need to keep the returned address, just keep it as void*.
Safest way :
static_cast<int>(reinterpret_cast<long>(void * your_variable));
long guarantees a pointer size on Linux on any machine. Windows has 32 bit long only on 64 bit as well. Therefore, you need to change it to long long instead of long in windows for 64 bits.
So reinterpret_cast has casted it to long type and then static_cast safely casts long to int, if you are ready do truncte the data.
There is no "correct" way to store a 64-bit pointer in an 32-bit integer. The problem is not with casting, but with the target type loosing half of the pointer. The 32 remaining bits stored inside int are insufficient to reconstruct a pointer to the thread function. Most answers just try to extract 32 useless bits out of the argument.
As Ferruccio said, int must be replaced with intptr_t to make the program meaningful.
If you call your thread creation function like this
pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));
then the void* arriving inside of myFcn has the value of the int you put into it. So you know you can cast it back like this
int myData = reinterpret_cast<int>(arg);
even though the compiler doesn't know you only ever pass myFcn to pthread_create in conjunction with an integer.
Edit:
As was pointed out by Martin, this presumes that sizeof(void*)>=sizeof(int). If your code has the chance to ever be ported to some platform where this doesn't hold, this won't work.
I would create a structure and pass that as void* to pthread_create
struct threadArg {
int intData;
long longData;
etc...
};
threadArg thrArg;
thrArg.intData = 4;
...
pthread_create(&thread, NULL, myFcn, (void*)(threadArg*)&thrArg);
void* myFcn(void* arg)
{
threadArg* pThrArg = (threadArg*)arg;
int computeSomething = pThrArg->intData;
...
}
Keep in mind that thrArg should exist till the myFcn() uses it.
What you may want is
int x = reinterpret_cast<int>(arg);
This allows you to reinterpret the void * as an int.
//new_fd is a int
pthread_create(&threads[threads_in_use] , NULL, accept_request, (void*)((long)new_fd));
//inside the method I then have
int client;
client = (long)new_fd;
Hope this helps
Don't pass your int as a void*, pass a int* to your int, so you can cast the void* to an int* and copy the dereferenced pointer to your int.
int x = *static_cast<int*>(arg);
In my case, I was using a 32-bit value that needed to be passed to an OpenGL function as a void * representing an offset into a buffer.
You cannot just cast the 32-bit variable to a pointer, because that pointer on a 64-bit machine is twice as long. Half your pointer will be garbage. You need to pass an actual pointer.
This will get you a pointer from a 32 bit offset:
int32 nOffset = 762; // random offset
char * pOffset = NULL; // pointer to hold offset
pOffset += nOffset; // this will now hold the value of 762 correctly
glVertexAttribPointer(binding, nStep, glType, glTrueFalse, VertSize(), pOffset);
A function pointer is incompatible to void* (and any other non function pointer)
Well it does this because you are converting a 64 bits pointer to an 32 bits integer so you loose information.
You can use a 64 bits integer instead howerver I usually use a function with the right prototype and I cast the function type :
eg.
void thread_func(int arg){
...
}
and I create the thread like this :
pthread_create(&tid, NULL, (void*(*)(void*))thread_func, (void*)arg);