Этот вопрос является почти дубликатом некоторых других, которые я обнаружил, но это в особенности касается POSIX и очень распространенного примера в pthreads, с которым я сталкивался несколько раз. Я в основном обеспокоен текущим положением дел (то есть C99 и POSIX.1-2008 или более поздней), но любая интересная историческая информация, конечно, также интересна.
Вопрос в основном сводится к тому, будет ли b всегда принимать то же значение, что и a в следующем коде:
long int a = /* some valid value */
void *ptr = (void *)a;
long int b = (long int)ptr;
Мне известно, что это обычно работает, но вопрос в том, правильно ли это делать (т. Е. Гарантируют ли стандарты C99 и / или POSIX, что это будет работать).
Когда дело доходит до C99, кажется, что нет, у нас есть 6.3.2.3:
.
5 Целое число может быть преобразовано в любой тип указателя. Кроме как
ранее указанный, результат определяется реализацией, не может быть
правильно выровнен, может не указывать на сущность
типа, и может быть представлением ловушки. 56)
6 Любой тип указателя может быть
преобразован в целочисленный тип. За исключением случаев, указанных ранее,
результат определяется реализацией. Если результат не может быть представлен
в целочисленном типе поведение не определено. Результат не должен быть
в диапазоне значений любого целочисленного типа.
Даже при использовании intptr_t стандарт, кажется, только гарантирует, что любой действительный void * может быть преобразован в intptr_t и обратно, но он не гарантирует, что любой intptr_t может быть преобразован в void * и обратно.
Однако все еще возможно, что стандарт POSIX позволяет это.
У меня нет особого желания использовать пустоту * в качестве места для хранения любой переменной (я нахожу это довольно уродливым, даже если POSIX должен это разрешить), но я чувствую, что должен спросить из-за распространенного примера использования pthreads_create функция, в которой аргумент start_routine является целым числом, и он передается как void * и преобразуется в int или long int в функции start_routine. Например, на этой man-странице есть такой пример (полный код см. По ссылке):
//Last argument casts int to void *
pthread_create(&tid[i], NULL, sleeping, (void *)SLEEP_TIME);
/* ... */
void * sleeping(void *arg){
//Casting void * back to int
int sleep_time = (int)arg;
/* ... */
}
Я также видел подобный пример в учебнике («Введение в параллельное программирование» Питера С. Пачеко). Учитывая, что это, кажется, распространенный пример, используемый людьми, которые должны знать этот материал намного лучше меня, я задаюсь вопросом, не ошибаюсь ли я, и на самом деле это безопасное и переносимое занятие.