Question about converting `void *` to `int` in C
I'm trying to pick my C skills again. I want to sum a sequence in different threads, each thread would return a pointer of the sum of a part of the sequence. However, when I tried to convert the void*
type value local_sum
to int
, problem occurred.
I tried to convert with sum += *(int*)local_sum;
, a segment error occurred and I got Process finished with exit code 11
.
I found that if I use sum += (int)local_sum;
, it would be okay. But I couldn't convince myself: shouldn't local_sum
be a void *
? Why it can be converted to int
with (int)local_sum
?
I'm so grateful it you could answer the problem.
The part that sum each process's return value is here:
int sum = 0;
for (int i = 0; i < NUM_THREADS; i ++) {
void * local_sum;
pthread_join(count_threads[i], (&local_sum));
sum += (int)local_sum;
}
The function of a thread is here:
void * count_thr(void *arg) {
int terminal = ARRAY_SIZE / NUM_THREADS;
int sum = 0;
for (int i = 0; i < terminal; i ++) {
sum += *((int*)arg + i);
}
return (void*)sum;
}
c pointers type-conversion pthreads
add a comment |
I'm trying to pick my C skills again. I want to sum a sequence in different threads, each thread would return a pointer of the sum of a part of the sequence. However, when I tried to convert the void*
type value local_sum
to int
, problem occurred.
I tried to convert with sum += *(int*)local_sum;
, a segment error occurred and I got Process finished with exit code 11
.
I found that if I use sum += (int)local_sum;
, it would be okay. But I couldn't convince myself: shouldn't local_sum
be a void *
? Why it can be converted to int
with (int)local_sum
?
I'm so grateful it you could answer the problem.
The part that sum each process's return value is here:
int sum = 0;
for (int i = 0; i < NUM_THREADS; i ++) {
void * local_sum;
pthread_join(count_threads[i], (&local_sum));
sum += (int)local_sum;
}
The function of a thread is here:
void * count_thr(void *arg) {
int terminal = ARRAY_SIZE / NUM_THREADS;
int sum = 0;
for (int i = 0; i < terminal; i ++) {
sum += *((int*)arg + i);
}
return (void*)sum;
}
c pointers type-conversion pthreads
12
Passing anint
inside the thevoid*
of pthreads, as opposed to pointing at one, has always been a dirty hack. And as all dirty hacks, they eventually break. Integer-to-pointer conversions have implementation-defined behavior (at the very least use uintptr_t). The solution is not to use dirty hacks, but to pass a pointer to malloc:ed data. The overhead execution time of dynamic allocation is nothing compared to the cost of creating and closing a thread.
– Lundin
Nov 16 '18 at 15:41
refer to c89: Convert an int to void* and back and the linked question Is it safe to cast an int to void pointer and back to int again?
– Sander De Dycker
Nov 16 '18 at 15:46
add a comment |
I'm trying to pick my C skills again. I want to sum a sequence in different threads, each thread would return a pointer of the sum of a part of the sequence. However, when I tried to convert the void*
type value local_sum
to int
, problem occurred.
I tried to convert with sum += *(int*)local_sum;
, a segment error occurred and I got Process finished with exit code 11
.
I found that if I use sum += (int)local_sum;
, it would be okay. But I couldn't convince myself: shouldn't local_sum
be a void *
? Why it can be converted to int
with (int)local_sum
?
I'm so grateful it you could answer the problem.
The part that sum each process's return value is here:
int sum = 0;
for (int i = 0; i < NUM_THREADS; i ++) {
void * local_sum;
pthread_join(count_threads[i], (&local_sum));
sum += (int)local_sum;
}
The function of a thread is here:
void * count_thr(void *arg) {
int terminal = ARRAY_SIZE / NUM_THREADS;
int sum = 0;
for (int i = 0; i < terminal; i ++) {
sum += *((int*)arg + i);
}
return (void*)sum;
}
c pointers type-conversion pthreads
I'm trying to pick my C skills again. I want to sum a sequence in different threads, each thread would return a pointer of the sum of a part of the sequence. However, when I tried to convert the void*
type value local_sum
to int
, problem occurred.
I tried to convert with sum += *(int*)local_sum;
, a segment error occurred and I got Process finished with exit code 11
.
I found that if I use sum += (int)local_sum;
, it would be okay. But I couldn't convince myself: shouldn't local_sum
be a void *
? Why it can be converted to int
with (int)local_sum
?
I'm so grateful it you could answer the problem.
The part that sum each process's return value is here:
int sum = 0;
for (int i = 0; i < NUM_THREADS; i ++) {
void * local_sum;
pthread_join(count_threads[i], (&local_sum));
sum += (int)local_sum;
}
The function of a thread is here:
void * count_thr(void *arg) {
int terminal = ARRAY_SIZE / NUM_THREADS;
int sum = 0;
for (int i = 0; i < terminal; i ++) {
sum += *((int*)arg + i);
}
return (void*)sum;
}
c pointers type-conversion pthreads
c pointers type-conversion pthreads
asked Nov 16 '18 at 15:20
Frost-Lee
514
514
12
Passing anint
inside the thevoid*
of pthreads, as opposed to pointing at one, has always been a dirty hack. And as all dirty hacks, they eventually break. Integer-to-pointer conversions have implementation-defined behavior (at the very least use uintptr_t). The solution is not to use dirty hacks, but to pass a pointer to malloc:ed data. The overhead execution time of dynamic allocation is nothing compared to the cost of creating and closing a thread.
– Lundin
Nov 16 '18 at 15:41
refer to c89: Convert an int to void* and back and the linked question Is it safe to cast an int to void pointer and back to int again?
– Sander De Dycker
Nov 16 '18 at 15:46
add a comment |
12
Passing anint
inside the thevoid*
of pthreads, as opposed to pointing at one, has always been a dirty hack. And as all dirty hacks, they eventually break. Integer-to-pointer conversions have implementation-defined behavior (at the very least use uintptr_t). The solution is not to use dirty hacks, but to pass a pointer to malloc:ed data. The overhead execution time of dynamic allocation is nothing compared to the cost of creating and closing a thread.
– Lundin
Nov 16 '18 at 15:41
refer to c89: Convert an int to void* and back and the linked question Is it safe to cast an int to void pointer and back to int again?
– Sander De Dycker
Nov 16 '18 at 15:46
12
12
Passing an
int
inside the the void*
of pthreads, as opposed to pointing at one, has always been a dirty hack. And as all dirty hacks, they eventually break. Integer-to-pointer conversions have implementation-defined behavior (at the very least use uintptr_t). The solution is not to use dirty hacks, but to pass a pointer to malloc:ed data. The overhead execution time of dynamic allocation is nothing compared to the cost of creating and closing a thread.– Lundin
Nov 16 '18 at 15:41
Passing an
int
inside the the void*
of pthreads, as opposed to pointing at one, has always been a dirty hack. And as all dirty hacks, they eventually break. Integer-to-pointer conversions have implementation-defined behavior (at the very least use uintptr_t). The solution is not to use dirty hacks, but to pass a pointer to malloc:ed data. The overhead execution time of dynamic allocation is nothing compared to the cost of creating and closing a thread.– Lundin
Nov 16 '18 at 15:41
refer to c89: Convert an int to void* and back and the linked question Is it safe to cast an int to void pointer and back to int again?
– Sander De Dycker
Nov 16 '18 at 15:46
refer to c89: Convert an int to void* and back and the linked question Is it safe to cast an int to void pointer and back to int again?
– Sander De Dycker
Nov 16 '18 at 15:46
add a comment |
3 Answers
3
active
oldest
votes
You're return
ing the value of int sum
by setting a void *
address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum
by casting a void *
to int
it will work.
void *
is used this way sometimes to return
either a value (e.g. int
) or an address to something (e.g. struct
).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a
, p
, and b
all have a value of 5
. p
does not point to a valid address. Trying to dereference p
would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %dn", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %dn", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by @Gerhardh, the sizeof(int)
and the sizeof(void *)
may be different. You may suffer data loss if the value of the void *
exceeds the maximum value a int
can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
1
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
2
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
a, p, and b all have a value of 5.a
andb
are not guaranteed to have the same value.
– David Brown
Nov 16 '18 at 20:36
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
|
show 1 more comment
You can't do *(int*)local_sum
because local_sum
is not an int*
cast to void*
. local_sum
is an int
cast to void*
. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit
only allows you to return a void*
, not an int
and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42
, it is highly unlikely there's anything at address 0x42
, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum;
or perhaps better with (int)(intptr_t)local_sum;
(though intptr_t
isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum;
so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
add a comment |
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void*
pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);
2
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53340689%2fquestion-about-converting-void-to-int-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
You're return
ing the value of int sum
by setting a void *
address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum
by casting a void *
to int
it will work.
void *
is used this way sometimes to return
either a value (e.g. int
) or an address to something (e.g. struct
).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a
, p
, and b
all have a value of 5
. p
does not point to a valid address. Trying to dereference p
would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %dn", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %dn", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by @Gerhardh, the sizeof(int)
and the sizeof(void *)
may be different. You may suffer data loss if the value of the void *
exceeds the maximum value a int
can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
1
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
2
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
a, p, and b all have a value of 5.a
andb
are not guaranteed to have the same value.
– David Brown
Nov 16 '18 at 20:36
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
|
show 1 more comment
You're return
ing the value of int sum
by setting a void *
address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum
by casting a void *
to int
it will work.
void *
is used this way sometimes to return
either a value (e.g. int
) or an address to something (e.g. struct
).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a
, p
, and b
all have a value of 5
. p
does not point to a valid address. Trying to dereference p
would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %dn", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %dn", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by @Gerhardh, the sizeof(int)
and the sizeof(void *)
may be different. You may suffer data loss if the value of the void *
exceeds the maximum value a int
can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
1
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
2
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
a, p, and b all have a value of 5.a
andb
are not guaranteed to have the same value.
– David Brown
Nov 16 '18 at 20:36
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
|
show 1 more comment
You're return
ing the value of int sum
by setting a void *
address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum
by casting a void *
to int
it will work.
void *
is used this way sometimes to return
either a value (e.g. int
) or an address to something (e.g. struct
).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a
, p
, and b
all have a value of 5
. p
does not point to a valid address. Trying to dereference p
would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %dn", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %dn", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by @Gerhardh, the sizeof(int)
and the sizeof(void *)
may be different. You may suffer data loss if the value of the void *
exceeds the maximum value a int
can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
You're return
ing the value of int sum
by setting a void *
address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum
by casting a void *
to int
it will work.
void *
is used this way sometimes to return
either a value (e.g. int
) or an address to something (e.g. struct
).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a
, p
, and b
all have a value of 5
. p
does not point to a valid address. Trying to dereference p
would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %dn", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %dn", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by @Gerhardh, the sizeof(int)
and the sizeof(void *)
may be different. You may suffer data loss if the value of the void *
exceeds the maximum value a int
can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
edited Nov 16 '18 at 15:58
answered Nov 16 '18 at 15:28
Fiddling Bits
7,09821938
7,09821938
1
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
2
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
a, p, and b all have a value of 5.a
andb
are not guaranteed to have the same value.
– David Brown
Nov 16 '18 at 20:36
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
|
show 1 more comment
1
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
2
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
a, p, and b all have a value of 5.a
andb
are not guaranteed to have the same value.
– David Brown
Nov 16 '18 at 20:36
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
1
1
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
" in our case, this behavior is desired." Really? It's not only a warning about conversion, it is about different size. That is not the part that is desired. You probably have 4 byte integers and 8 byte pointers.
– Gerhardh
Nov 16 '18 at 15:47
2
2
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
note that the behavior of this is implementation defined
– Sander De Dycker
Nov 16 '18 at 15:47
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
@Gerhardh Excellent point.
– Fiddling Bits
Nov 16 '18 at 15:59
a, p, and b all have a value of 5.
a
and b
are not guaranteed to have the same value.– David Brown
Nov 16 '18 at 20:36
a, p, and b all have a value of 5.
a
and b
are not guaranteed to have the same value.– David Brown
Nov 16 '18 at 20:36
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
@DavidBrown Of course, this is undefined behavior. On my machine, this behavior is so.
– Fiddling Bits
Nov 16 '18 at 20:38
|
show 1 more comment
You can't do *(int*)local_sum
because local_sum
is not an int*
cast to void*
. local_sum
is an int
cast to void*
. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit
only allows you to return a void*
, not an int
and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42
, it is highly unlikely there's anything at address 0x42
, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum;
or perhaps better with (int)(intptr_t)local_sum;
(though intptr_t
isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum;
so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
add a comment |
You can't do *(int*)local_sum
because local_sum
is not an int*
cast to void*
. local_sum
is an int
cast to void*
. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit
only allows you to return a void*
, not an int
and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42
, it is highly unlikely there's anything at address 0x42
, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum;
or perhaps better with (int)(intptr_t)local_sum;
(though intptr_t
isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum;
so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
add a comment |
You can't do *(int*)local_sum
because local_sum
is not an int*
cast to void*
. local_sum
is an int
cast to void*
. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit
only allows you to return a void*
, not an int
and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42
, it is highly unlikely there's anything at address 0x42
, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum;
or perhaps better with (int)(intptr_t)local_sum;
(though intptr_t
isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum;
so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
You can't do *(int*)local_sum
because local_sum
is not an int*
cast to void*
. local_sum
is an int
cast to void*
. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit
only allows you to return a void*
, not an int
and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42
, it is highly unlikely there's anything at address 0x42
, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum;
or perhaps better with (int)(intptr_t)local_sum;
(though intptr_t
isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum;
so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
answered Nov 16 '18 at 15:41
PSkocik
32.2k54770
32.2k54770
add a comment |
add a comment |
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void*
pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);
2
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
add a comment |
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void*
pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);
2
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
add a comment |
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void*
pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void*
pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);
answered Nov 16 '18 at 16:15
Morpheus
1385
1385
2
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
add a comment |
2
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
2
2
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
Casting should work regardless of endianness. On a (very theoretical) big-endian machine where ints are half the width of pointers, the union approach would fail to extract the value while a cast shouldn't.
– PSkocik
Nov 16 '18 at 16:21
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53340689%2fquestion-about-converting-void-to-int-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
12
Passing an
int
inside the thevoid*
of pthreads, as opposed to pointing at one, has always been a dirty hack. And as all dirty hacks, they eventually break. Integer-to-pointer conversions have implementation-defined behavior (at the very least use uintptr_t). The solution is not to use dirty hacks, but to pass a pointer to malloc:ed data. The overhead execution time of dynamic allocation is nothing compared to the cost of creating and closing a thread.– Lundin
Nov 16 '18 at 15:41
refer to c89: Convert an int to void* and back and the linked question Is it safe to cast an int to void pointer and back to int again?
– Sander De Dycker
Nov 16 '18 at 15:46