将参数作为 int 传递给线程 - 警告:从不同大小的整数转换为指针
Passing argument as int to thread - Warning: cast to pointer from integer different size
将参数作为 int 而不是 long 传递给 pthread_create 有什么区别?
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
我从 POSIX Threads Programming 中获取了代码,它仅在将函数参数声明为 long
时起作用
void *PrintHello(void *threadid) {
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0;t<NUM_THREADS;t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
您将参数视为 long
而不是指向 long
的指针。这意味着您依赖于 long
和 void *
具有相同的数据大小。如果 int
有不同的大小,这可以解释为什么会出错。在任何情况下,您都应该在参数中传递 &t
并将其相应地提取为 *threadid
:
void *PrintHello(void *threadid) {
long tid;
tid = *((long *)threadid);
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
static long tid[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++) {
printf("In main: creating thread %ld\n", t);
tid[t] = t;
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&tid[t]);
if(rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
更新:将线程 ID 存储在数组 tid
中。
在这种情况下,问题与线程无关,而是与void *
和整数类型之间的转换有关。 'c' 允许您在这些类型之间自由转换,但您必须注意转换对象的大小。
例如,在 64 位模式下的 x86 上,void*
的大小是 64 位(8 字节)。与long int
的大小相同。但是,int
的大小是 32 位(4 字节)。
因此,将 int
转换为 (void*)
会将 int 符号扩展为 64 位并将其分配给 void。编译器给你一个警告,因为转换中的大小不同但这里没有违反标准。
从 void *
转换回 int
也会生成警告。此转换将丢失高 32 位。但是如果 void *
本身是从一个 int 赋值的,它将正确地转换为 int
。但是,如果你尝试将它转换为 long
而原来的 int
是负数,你将得到一个完全不同的图片,它不会与原来的 int
相同,所有上32 位将是原始符号扩展的结果。
为了让图片更有趣,在不同的平台上会有不同的效果。例如,在 32 位平台上,long int
的大小可能与 int
的大小和 void*
的大小相同。
long int
的潜在大小通常与 void*
的大小相匹配。至少它适用于一些平台。因此,这种转换是最安全的。
因此,最好的解决方案是在编写跨平台代码时避免此类转换。
以下建议代码:
- 干净地编译
- 执行所需的功能
- 即使发生错误也会自行清理
- 正确地(使用
perror()
)输出OPs错误消息和系统认为发生错误的文本原因stderr
。
- 使用签名:
int main( void )
因此编译器没有关于未使用参数的消息。
- 由于循环计数器不能小于 0,因此循环计数器使用变量类型
size_t
。
- 正确地将
pthread_t
数组初始化(为 0)为 0,因此可用于清理操作
- 更正了对
printf()
的调用中的格式说明符,期望变量的类型为:size_t
main()
函数是否在 main()
函数退出之前正确等待线程退出
- 合并了一个新功能:
cleanup()
以在退出程序之前正确清理任何线程。
- 为了便于阅读和理解,使用适当的水平间距和垂直间距。
现在,建议的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREADS 20
void *PrintHello( void *arg )
{
size_t threadNum = (size_t)arg;
printf( "Hello World! It's me, thread #%lu!\n", threadNum );
pthread_exit( NULL );
}
void cleanup( pthread_t *threads )
{
for( size_t i=0; i<NUM_THREADS; i++ )
{
if( threads[i] )
{
pthread_join( threads[i], NULL );
}
}
}
int main( void )
{
pthread_t threads[ NUM_THREADS ] = {0};
for( size_t t = 0; t < NUM_THREADS; t++ )
{
printf( "In main: creating thread %ld\n", t );
if( pthread_create( &threads[t], NULL, PrintHello, (void *)t ) )
{
perror( "pthread_create() failed" );
cleanup( threads );
exit( EXIT_FAILURE );
}
}
cleanup( threads );
/* Last thing that main() should do */
pthread_exit( NULL );
}
这里是一个典型的 运行 提议的代码在没有错误发生时的输出:
In main: creating thread 0
In main: creating thread 1
Hello World! It's me, thread #0!
In main: creating thread 2
In main: creating thread 3
In main: creating thread 4
Hello World! It's me, thread #3!
In main: creating thread 5
Hello World! It's me, thread #4!
In main: creating thread 6
In main: creating thread 7
Hello World! It's me, thread #6!
Hello World! It's me, thread #5!
In main: creating thread 8
Hello World! It's me, thread #7!
In main: creating thread 9
Hello World! It's me, thread #8!
In main: creating thread 10
In main: creating thread 11
In main: creating thread 12
Hello World! It's me, thread #10!
Hello World! It's me, thread #9!
Hello World! It's me, thread #11!
In main: creating thread 13
In main: creating thread 14
Hello World! It's me, thread #13!
In main: creating thread 15
Hello World! It's me, thread #12!
Hello World! It's me, thread #14!
In main: creating thread 16
Hello World! It's me, thread #15!
In main: creating thread 17
In main: creating thread 18
In main: creating thread 19
Hello World! It's me, thread #19!
Hello World! It's me, thread #16!
Hello World! It's me, thread #17!
Hello World! It's me, thread #18!
Hello World! It's me, thread #1!
Hello World! It's me, thread #2!
将参数作为 int 而不是 long 传递给 pthread_create 有什么区别?
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
我从 POSIX Threads Programming 中获取了代码,它仅在将函数参数声明为 long
时起作用void *PrintHello(void *threadid) {
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0;t<NUM_THREADS;t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
您将参数视为 long
而不是指向 long
的指针。这意味着您依赖于 long
和 void *
具有相同的数据大小。如果 int
有不同的大小,这可以解释为什么会出错。在任何情况下,您都应该在参数中传递 &t
并将其相应地提取为 *threadid
:
void *PrintHello(void *threadid) {
long tid;
tid = *((long *)threadid);
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
static long tid[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++) {
printf("In main: creating thread %ld\n", t);
tid[t] = t;
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&tid[t]);
if(rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
更新:将线程 ID 存储在数组 tid
中。
在这种情况下,问题与线程无关,而是与void *
和整数类型之间的转换有关。 'c' 允许您在这些类型之间自由转换,但您必须注意转换对象的大小。
例如,在 64 位模式下的 x86 上,void*
的大小是 64 位(8 字节)。与long int
的大小相同。但是,int
的大小是 32 位(4 字节)。
因此,将 int
转换为 (void*)
会将 int 符号扩展为 64 位并将其分配给 void。编译器给你一个警告,因为转换中的大小不同但这里没有违反标准。
从 void *
转换回 int
也会生成警告。此转换将丢失高 32 位。但是如果 void *
本身是从一个 int 赋值的,它将正确地转换为 int
。但是,如果你尝试将它转换为 long
而原来的 int
是负数,你将得到一个完全不同的图片,它不会与原来的 int
相同,所有上32 位将是原始符号扩展的结果。
为了让图片更有趣,在不同的平台上会有不同的效果。例如,在 32 位平台上,long int
的大小可能与 int
的大小和 void*
的大小相同。
long int
的潜在大小通常与 void*
的大小相匹配。至少它适用于一些平台。因此,这种转换是最安全的。
因此,最好的解决方案是在编写跨平台代码时避免此类转换。
以下建议代码:
- 干净地编译
- 执行所需的功能
- 即使发生错误也会自行清理
- 正确地(使用
perror()
)输出OPs错误消息和系统认为发生错误的文本原因stderr
。 - 使用签名:
int main( void )
因此编译器没有关于未使用参数的消息。 - 由于循环计数器不能小于 0,因此循环计数器使用变量类型
size_t
。 - 正确地将
pthread_t
数组初始化(为 0)为 0,因此可用于清理操作 - 更正了对
printf()
的调用中的格式说明符,期望变量的类型为:size_t
main()
函数是否在main()
函数退出之前正确等待线程退出- 合并了一个新功能:
cleanup()
以在退出程序之前正确清理任何线程。 - 为了便于阅读和理解,使用适当的水平间距和垂直间距。
现在,建议的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREADS 20
void *PrintHello( void *arg )
{
size_t threadNum = (size_t)arg;
printf( "Hello World! It's me, thread #%lu!\n", threadNum );
pthread_exit( NULL );
}
void cleanup( pthread_t *threads )
{
for( size_t i=0; i<NUM_THREADS; i++ )
{
if( threads[i] )
{
pthread_join( threads[i], NULL );
}
}
}
int main( void )
{
pthread_t threads[ NUM_THREADS ] = {0};
for( size_t t = 0; t < NUM_THREADS; t++ )
{
printf( "In main: creating thread %ld\n", t );
if( pthread_create( &threads[t], NULL, PrintHello, (void *)t ) )
{
perror( "pthread_create() failed" );
cleanup( threads );
exit( EXIT_FAILURE );
}
}
cleanup( threads );
/* Last thing that main() should do */
pthread_exit( NULL );
}
这里是一个典型的 运行 提议的代码在没有错误发生时的输出:
In main: creating thread 0
In main: creating thread 1
Hello World! It's me, thread #0!
In main: creating thread 2
In main: creating thread 3
In main: creating thread 4
Hello World! It's me, thread #3!
In main: creating thread 5
Hello World! It's me, thread #4!
In main: creating thread 6
In main: creating thread 7
Hello World! It's me, thread #6!
Hello World! It's me, thread #5!
In main: creating thread 8
Hello World! It's me, thread #7!
In main: creating thread 9
Hello World! It's me, thread #8!
In main: creating thread 10
In main: creating thread 11
In main: creating thread 12
Hello World! It's me, thread #10!
Hello World! It's me, thread #9!
Hello World! It's me, thread #11!
In main: creating thread 13
In main: creating thread 14
Hello World! It's me, thread #13!
In main: creating thread 15
Hello World! It's me, thread #12!
Hello World! It's me, thread #14!
In main: creating thread 16
Hello World! It's me, thread #15!
In main: creating thread 17
In main: creating thread 18
In main: creating thread 19
Hello World! It's me, thread #19!
Hello World! It's me, thread #16!
Hello World! It's me, thread #17!
Hello World! It's me, thread #18!
Hello World! It's me, thread #1!
Hello World! It's me, thread #2!