[英]Question about converting `void *` to `int` in C
I'm trying to pick my C skills again. 我想再次选择我的C技能。 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. 但是,当我尝试将
void*
类型值local_sum
转换为int
,出现了问题。
I tried to convert with sum += *(int*)local_sum;
我试着用
sum += *(int*)local_sum;
, a segment error occurred and I got Process finished with exit code 11
. ,发生了一个段错误,我
Process finished with exit code 11
了Process finished with exit code 11
。
I found that if I use sum += (int)local_sum;
我发现如果我使用
sum += (int)local_sum;
, it would be okay. ,没关系。 But I couldn't convince myself: shouldn't
local_sum
be a void *
? 但我无法说服自己:
local_sum
不local_sum
是一个void *
? Why it can be converted to int
with (int)local_sum
? 为什么可以使用
(int)local_sum
将其转换为int
?
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;
}
You're return
ing the value of int sum
by setting a void *
address to it. 您将通过为其设置
void *
地址来return
int sum
的值。 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 *
为int
来获得sum
的值,那么它将起作用。
void *
is used this way sometimes to return
either a value (eg int
) or an address to something (eg struct
). void *
以这种方式使用有时return
值(例如int
)或地址(例如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
. a
, p
和b
都具有值5
。 p
does not point to a valid address. p
不指向有效地址。 Trying to dereference p
would result in undefined behavior: 尝试取消引用
p
会导致未定义的行为:
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 %d\n", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %d\n", 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. 发出警告是因为,正如@Gerhardh所指出的,
sizeof(int)
和sizeof(void *)
可能不同。 You may suffer data loss if the value of the void *
exceeds the maximum value a int
can hold. 如果
void *
的值超过int
可以容纳的最大值,则可能会丢失数据。
Output 产量
$ ./main.exe 5 0x5 5 2147483647 0x80000000 -2147483648
You can't do *(int*)local_sum
because local_sum
is not an int*
cast to void*
. 你不能做
*(int*)local_sum
因为local_sum
不是int*
cast to void*
。 local_sum
is an int
cast to void*
. local_sum
是一个int
为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). 这是重新解释为地址的数量,但仅用于传输目的,因为
pthread_exit
只允许你返回void*
,而不是int
因为标准中明确允许实现定义的转换( 6.3.2.3p5 , 6.3.2.3p6 )在整数和数字之间,只要值适合(如果它们不适合,UB)。 If you return, eg, 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;
如果你返回,例如,
0x42
,那么地址0x42
处的任何东西都不太可能,所以你应该忘记取消引用它,而应该将它转换回整数ASAP,或者使用(int)local_sum;
or perhaps better with (int)(intptr_t)local_sum;
或者更好用
(int)(intptr_t)local_sum;
(though intptr_t
isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum;
(虽然不保证
intptr_t
存在)或(也许最好)与(int)(intmax_t)local_sum;
so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms. 以避免在LP64平台上有关转换为不同大小的整数的可能的编译器警告。
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: 然后,例如,您可以安全地重新解释
void*
指针:
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.