Использование битовых операций для "выключения" двоичных цифр указателя

Вопрос:

Я смог использовать битовые операции для “выключения” двоичных цифр числа.

Пример:
x = x & ~ (1 << 0)
x = x & ~ (1 << 1)
(и повторите, пока желаемое количество цифр, начинающихся справа, не будет изменено на 0)

Я хотел бы применить этот метод к адресу указателя.

К сожалению, оператор & не может использоваться с указателями. Используя те же строки кода, что и выше, где x является указателем, компилятор говорит “недопустимые операнды для двоичных & (имеют int и int)”.

Я попытался нарисовать указатели как ints, но это не работает, поскольку я предполагаю, что ints слишком малы (и я только понял, что мне не разрешено делать бросок).

(обратите внимание: хотя это часть проблемы с домашним заданием, я уже объяснил, почему мне нужно отключить некоторые цифры после пары часов, поэтому я в порядке. Я просто пытаюсь понять, может получить умную технику, чтобы делать то, что я хочу здесь делать).

Ограничения: я не могу использовать циклы, условные обозначения, любые специальные функции, константы больше 255, деление, мода.

(изменение: добавлены ограничения внизу)

Ответ №1

Используйте uintptr_t из <stdint.h>. Вы всегда должны использовать неподписанные типы для (u)intptr_t бит, и (u)intptr_t специально выбран, чтобы иметь возможность удерживать значение указателя.

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

Изменить: из вашего комментария Я понимаю, что вы не планируете разыменовывать спрятанный указатель вообще, поэтому для вас не существует неопределенного поведения. Вот как вы можете проверить, имеют ли ваши указатели один и тот же 64-байтовый блок:

uintptr_t p1 = (uintptr_t)yourPointer1;
uintptr_t p2 = (uintptr_t)yourPointer2;
uintptr_t mask = ~(uintptr_t)63u; // Shave off 5 low-order bits

return (p1 & mask) == (p2 & mask);

Ответ №2

Стандартная библиотека языка C включает в себя (необязательный, хотя) тип intptr_t, для которого существует гарантия того, что “любой действительный указатель на void может быть преобразован в этот тип, а затем преобразован обратно в указатель на void, и результат будет сравниваться с исходным указателем “.

Конечно, если вы выполняете побитовое действие над целым числом, то результатом является неопределенное поведение.

Ответ №3

Редактировать:

Как несчастный ха-ха. Мне нужна функция для отображения двух указателей в одном 64-байтовом блоке памяти. Это верно, если каждая цифра, но наименее значимые 6 цифр их двоичных представлений равны. Убедившись, что последние 6 цифр являются одинаковыми (например: 0), я могу вернуть true, если оба указателя равны. Ну, по крайней мере, я надеюсь.

Вы должны быть в состоянии проверить, находятся ли они в одном и том же блоке памяти примерно так:

if ((char *)high_pointer - (char *)low_pointer < 64) {
// do stuff
}

Edit2: Вероятно, это неопределенное поведение, как указано Крисом.

Оригинальное сообщение:

Вероятно, вы ищете intptr_t или uintptr_t. В стандарте указано, что вы можете использовать эти типы и от них к указателям и иметь значение, равное оригиналу.

Однако, несмотря на то, что он является стандартным типом, он является необязательным, поэтому некоторые реализации библиотек могут не выполнять его. Некоторые архитектуры могут даже не представлять указатели как целые числа, поэтому такой тип не имеет смысла.

Он по-прежнему лучше, чем кастинг в int и от int или long так как он гарантированно работает над реализациями, которые его предоставляют. В противном случае, по крайней мере, во время компиляции вы узнаете, что ваша программа будет разбита на определенную реализацию/архитектуру.

(О, и, как указывали другие ответы, вручную изменяя указатель при приведении в целочисленный тип и разыменовывая это неопределенное поведение)

Оцените статью
TechArks.Ru
Добавить комментарий