Этот вопрос почти дублирует некоторые другие, которые я нашел, но это касается POSIX и очень распространенного примера в pthreads, с которым я сталкивался несколько раз. Меня в основном интересует текущее состояние дел (т.е. C99 и POSIX.1-2008 или новее), но любая интересная историческая информация также интересна.
Вопрос в основном сводится к тому, будет ли b всегда принимать то же значение, что и в следующем коде:
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 позволяет это.
У меня нет большого желания использовать void * в качестве места хранения для любой переменной (я нахожу ее довольно уродливой, даже если 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;
/* ... */
}
Я также видел аналогичный пример в учебнике ( "Введение в параллельное программирование" Питера С. Пачеко). Учитывая, что это, кажется, обычный пример, используемый людьми, которые должны знать этот материал намного лучше меня, мне интересно, ошибаюсь ли я, и это действительно безопасная и портативная вещь, которую нужно делать.