Стандарт C разрешает преобразования между целым числом и указателем, однако не объясняет, как именно это должно происходить. Это зависит от каждой конкретной реализации.
Раздел 6.3.2.3 p5-6 стандарта C описывает эти преобразования:
5 Целое число может быть преобразовано в любой тип указателя. За исключением случаев, указанных ранее, результат определяется реализацией, может быть неправильно выровнен, может не указывать на сущность указанного типа и может быть представлением ловушки.
6 Любой тип указателя может быть преобразован в целочисленный тип. За исключением случаев, указанных ранее, результат определяется реализацией. Если результат не может быть представлен в целочисленном типе, поведение не определено. Результат не обязательно должен находиться в диапазоне значений любого целочисленного типа.
В частности, в gcc то, что вы делаете, будет работать, однако это не гарантирует работу на всех компиляторах или архитектурах.
Что гарантированно работает, так это получение адреса составного литерала:
void *vp = &(uint8_t){5};
uint8_t i = *(uint8_t *)vp;
Это создает временный объект типа uint8_t
и получает его адрес. Затем этот адрес можно преобразовать в void *
и обратно, что полностью соответствует стандарту, как указано в параграфе 1 раздела 6.3.2.3:
Указатель на void
может быть преобразован в или из указателя на объект любого типа. Указатель на объект любого типа может быть преобразован в указатель на void
и обратно; результат будет равен исходному указателю.
Время жизни составного литерала равно времени жизни блока, в котором он определен. Поэтому, пока указатель не используется после окончания этого блока, он будет работать.
Однако, если вы собираетесь передать его функции, которая запускает поток, вам лучше динамически выделять память для значения и передавать его. В противном случае вы рискуете, что функция, в которой определен составной литерал, вернется во время выполнения функции потока, которая может попытаться использовать этот указатель.
person
dbush
schedule
01.07.2021
void *
иuint8_t
. Вот для чего нужны профсоюзы. - person user3386109   schedule 01.07.2021uintptr_t
. - person Barmar   schedule 01.07.2021warning: initialization of ‘void *’ from ‘int’ makes pointer from integer without a cast
так говорит GCC, и это без явного включения каких-либо предупреждений. Также, согласно комментарию @dbush, не могли бы вы немного расширить свой вопрос, поскольку неясно, что вы пытаетесь сделать и почему. - person Rodney   schedule 01.07.2021void *
илиuint8_t
? Или, другими словами, что такое сигнатура функции? - person user3386109   schedule 01.07.2021void *
в качестве типа определяемого пользователем параметра обратного вызова является очень распространенной идиомой. Вы зарегистрировали функцию обратного вызова, передав ее как определяемую пользователем. параметр, поэтому функция обратного вызова знает, что с ним делать при вызове с ним. Я считаю, что причина в том, чтоvoid *
достаточно велик, чтобы содержать любой тип указателя, в который вы хотите его применить. - person marko   schedule 01.07.2021