Вы не можете сделать арифметику указателей для "void *", потому что void не имеет размера.
При добавлении или вычитании указателя это всегда выполняется в единицах sizeof(*p)
. Значение: если вы добавляете единицу к указателю int, его значение увеличивается на 4 (потому что размер целого числа равен 4). Поэтому, когда вы добавляете к пустому указателю, он должен увеличиваться на размер пустого. Но пустота не имеет размера.
Однако, некоторые компиляторы готовы выполнять арифметику на void *
, и они относятся к ней как char *
. С этими компиляторами вы могли бы реализовать эти функции без приведения. Но это не стандартно.
Другой момент заключается в том, что не все операторы применимы для указателей. Сложение и вычитание есть, но умножение, деление и модуль не. Поэтому, если вы хотите проверить младшие биты указателя, чтобы узнать, выровнен ли он, вы приведете его к длинному.
Почему долго? Предполагается, что long равен указателю, что верно для Linux, но не для Windows. Правильный тип - uintptr_t. Однако, если вас интересуют только младшие биты, не имеет значения, теряете ли вы старшие биты во время чтения. Так что приведение к int тоже сработало бы.