joe
joe

Reputation: 9503

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);
}

Upvotes: 0

Views: 1134

Answers (2)

Anon Mail
Anon Mail

Reputation: 4770

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.

Upvotes: 3

Jens
Jens

Reputation: 9416

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);

Upvotes: 1

Related Questions