почему это кастинг для действительного указателя void?

Я отлаживаю программу из книги. Программа работает, но я не понимаю одну строку, о которой я прокомментирую ниже.

#include  #include  /* Compute successive prime numbers (very inefficiently). Return the Nth prime number, where N is the value pointed to by *ARG. */ void* compute_prime (void* arg) { int candidate = 2; int n = *((int*) arg); while (1) { int factor; int is_prime = 1; /* Test primality by successive division. */ for (factor = 2; factor < candidate; ++factor) if (candidate % factor == 0) { is_prime = 0; break; } /* Is this the prime number we're looking for? */ if (is_prime) { if (--n == 0) /* Return the desired prime number as the thread return value. */ return (void*) candidate; // why is this casting valid? (candidate is not even a pointer) } ++candidate; } return NULL; } int main () { pthread_t thread; int which_prime = 5000; int prime; /* Start the computing thread, up to the 5,000th prime number. */ pthread_create (&thread, NULL, &compute_prime, &which_prime); /* Do some other work here... */ /* Wait for the prime number thread to complete, and get the result. */ pthread_join (thread, (void*) &prime); /* Print the largest prime it computed. */ printf(“The %dth prime number is %d.\n”, which_prime, prime); return 0; } 

    Это неверно. Это просто происходит, если sizeof(int) == sizeof(void *) , что происходит во многих системах.

    У void * гарантируется только возможность удерживать указатели на объекты данных.

    Здесь есть вопросник C по этому вопросу.

    Как целые числа преобразуются в указатели и из них? Могу ли я временно ввести целое число в указатель , или наоборот?

    Преобразования с указателями на целые и целочисленные в указатели определяются по реализации (см. Вопрос 11.33), и нет никакой гарантии, что указатели могут быть преобразованы в целые и обратно, без изменений

    Приведение указателей в целые числа или целые числа в указатели никогда не было хорошей практикой

    Что вы подразумеваете под «действительным»?

    Вы явно запрашиваете приведение, а язык или компилятор не остановит вас. Полезно ли это совсем другое дело. Действительно, как вы говорите, candidate не является указателем, и он не указывает ни на что полезное. Получатель возвращаемого значения должен знать, что с ним делать (например, отбросить его обратно до int , хотя это не гарантирует, что это возвращает исходное значение).

    Если вам никогда не понадобится значение, вы можете просто вернуть 0 . Просто pthread_create ожидает в качестве аргумента функции указателя типа void*(*)(void*) , поэтому ваша функция должна вернуть void* . Если вам это не нужно, вы можете игнорировать его и просто вернуть любое старое значение.

    (В других ситуациях функция streamа могла выбрать malloc() некоторую память, заполнить ее данными результата и вернуть указатель на этот адрес, поэтому void* в некотором смысле является «наиболее общим» типом возврата для C которая должна быть максимально гибкой, не зная, как она будет использоваться.)

    В то время как другие правы, что C оставляет результаты реализации данного литья, ваш код (используя pthreads) зависит от POSIX, для которого требуется модель памяти, где компилятор должен будет изо всех сил нарушать то, что вы делаете. Также все реалии POSIX реального мира – это ILP32 или LP64, что означает, что любое значение int будет помещаться в указатель.

    Хотя «уродливый» с формальной точки зрения, использование int void * casts с аргументом нити или возвращаемым значением для передачи небольших целочисленных данных обычно является меньшим из двух зол, другой выбор – malloc(sizeof(int)) в одном нить и free в другом, что не только существенно увеличивает значительные затраты, но также может быть патологически плохой на некоторых распределителях, настроенных только для случая, когда выделение streamа и освобождение streamа одинаковы.

    Один из способов избежать обоих зол: если создатель streamа будет существовать некоторое время и в конечном итоге вызывает pthread_join , вы можете передать новый stream указателю на объект данных в стеке создателя или в память, иначе принадлежащую создателю , Затем новый stream может записать свой результат в это место до его завершения.