简体   繁体   中英

Why casting long can solve “warning: cast to pointer from integer of different size”?

I am practicing concurrent programming. My ultimate goal is applying the multiple thread on OpenCV and 3rd party software. I am reading the following URL.
http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm

      rc = pthread_create(&threads[i], NULL, 
                          PrintHello, (void *)i);

It returns me an error.

$ g++ simpleThread.cpp -lpthread
simpleThread.cpp: In function ‘int main()’:
simpleThread.cpp:25:47: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
                           PrintHello, (void *)i);

Then I read http://stackoverflow.com/questions/21323628/warning-cast-to-from-pointer-from-to-integer-of-different-size Add long

  rc = pthread_create(&threads[i], NULL, 
                      PrintHello, (void *)(long)i);

Program works.

Question :
I don't understand at all. Why I have to put long in here?
Where, what topic, book, URLs I can start?

Update :
Thank you everyone for your attention. Casting by long returns me acceptable result.

rc = pthread_create(&threads[i], NULL, 
                          PrintHello, (void*)(long)i);

Run the program.

$./simpleThreadLong.out 
main() : creating thread, 0
main() : creating thread, 1
Hello World! Thread ID, 0
main() : creating thread, Hello World! Thread ID, 2
1
main() : creating thread, 3
Hello World! Thread ID, 2
main() : creating thread, 4
Hello World! Thread ID, 3
Hello World! Thread ID, 4

Whereas ampersand returns unknown ID.

  rc = pthread_create(&threads[i], NULL, 
                      PrintHello, &i);

Run the program.

./simpleThreadAmpersand.out 
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
Hello World! Thread ID, 140722119501784
Hello World! Thread ID, 140722119501784
Hello World! Thread ID, 140722119501784
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 140722119501784
Hello World! Thread ID, 140722119501784

Update2:

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main ()
{
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   for( i=0; i < NUM_THREADS; i++ ){
      cout << "main() : creating thread, " << i << endl;
      //rc = pthread_create(&threads[i], NULL, 
      //                    PrintHello, (void *)(long)i);
      rc = pthread_create(&threads[i], NULL, 
                          PrintHello, &i);
      if (rc){
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

I assume because on your platform, a pointer is the same size as long .

In general, you don't want to be casting integer types to pointers. And I'm thinking that functions takes an address of it's argument so your code won't work. You probably need to pass & i .

EDIT After reading your link it looks like the example is using a bit of a hack in the first example and is doing exactly what I don't recommend above. But then second example he/she is doing it correctly.

EDIT 2 After seeing the MCVE you need to change this:

   long tid;
   tid = (long)threadid;

to this:

   int tid;
   tid = *((int *)threadid);

But that will produce spurious results because the variable i in main (whose address you are passing into each thread) is changing. Plus it is not protected by some synchronization mechanism.

Bottom line is you can use the hack they use in the first example of your post to make it work. But the carefully read how the do the second example.

On most 64-bit platforms, standard sizes for int and pointers are different. int is often still 32-bit, but pointers are 64-bit since they must be able to represent 64-bit addresses. You can easily check it on your platform by printing

std::cout << sizeof(int) << std::endl << sizeof(void*) << std::endl;

On my Linux system, this prints 4 and 8. The compiler just complains that you are casting a signed 32-bit value to an unsigned 64-bit value.

The POSIX thread API gives you the possibility to pass arbitrary data to the created thread. Arbitrary data in C means something of unknown size and type, and the only thing you know is an address to an object. This is a void* . Another way to fix your problem is to dynamically allocate the data and pass the address to the thread:

rc = pthread_create(&threads[i], NULL, 
                          PrintHello, new int(i) );

PrintHello than has to cast the void* to an int* to use the data.

void PrintHello(void* data) {
    std::unique_ptr<int> i( static_cast<int*>(data) );
}

With C++11, you can skip all that and just use a better abstraction:

void PrintHello(int i);

int i = 42;
auto t1 = std::thread( PrintHello, i ) { /* do something with i */ };
// or preferably use std::async
auto f = std::async(std::launch::async, PrintHello, i);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM