Сравнение двух указателей void с различными объектами, определенными в C++?
вдохновленный ответ о динамическом приведении к void*
:
... bool eqdc(B* b1, B *b2) { return dynamic_cast<void*>(b1) == dynamic_cast<void*>(b2); } ... int main() { DD *dd = new DD(); D1 *d1 = dynamic_cast<D1*>(dd); D2 *d2 = dynamic_cast<D2*>(dd); ... eqdc(d1, d2) ...
мне интересно, полностью ли определено поведение на C++ (в соответствии со стандартом 03 или 11) до сравните два указателя пустоты Для (в)равенства ссылки к действительный, а различные объекты.
в более общем плане, но, возможно, не так актуально, сравнивает (==
или !=
) два значения типа void*
всегда определено или требуется, чтобы они содержали указатель на допустимый объект/область памяти?
2 ответов
C говорит:
два указателя равны, если и только если оба нулевые указатели, расположенные указатели тот же объект (включая указатель на объект и подобъект в его начале) или функция, оба являются указателями на один последний элемент одного и того же объекта массива, или один является указателем к одному концу одного объекта массива, а другой-указатель на начало другого объект array, который происходит сразу после первого объекта array в адрес пространство.
в C++ говорит:
два указателя одного типа равны, если и только если они оба нулевые, оба указывают на одну и ту же функцию, или оба представляют один и тот же адрес.
следовательно, это означало бы, что:
a)
это полностью определенное поведение в C++ (в соответствии со стандартом 03 или 11), чтобы сравнить два указателя void для равенства (in), которые указывают на действительные, но разные объекты.
Так что да, как на C, так и на C++. Вы можете сравнить их, и в этом случае они будут сравниваться как истинные, если они указывают на один и тот же объект. Это просто.
b)
это сравнение (==или != ) два значения типа void * всегда определены или требуется, чтобы они содержали указатель на допустимый объект/область памяти?
опять же, сравнение четко определено (стандарт говорит "если и только если", поэтому каждое сравнение двух указателей четкий.) Зато...
- C++ говорит с точки зрения "адреса", поэтому я думаю, что это означает, что стандарт требует, чтобы это работало"как мы ожидали",
- C, однако, требует, чтобы оба указателя были либо нулевыми, либо указывали на объект или функцию, либо на один элемент за объектом массива. Это, если мои навыки чтения не отключены, означает, что если на данной платформе у вас есть два указателя с одинаковым значением, но не указывающие на допустимый объект( например, смещенный), сравнивая они должны быть четко определены и давать ложные результаты.
Это удивительно!
об этом не так работает GCC:
int main() {
void* a = (void*)1; // misaligned, can't point to a valid object
void* b = a;
printf((a == b) ? "equal" : "not equal");
return 0;
}
результат:
equal
может быть, это UB в C, чтобы иметь указатель, который не является нулевым указателем, а не указывает на объект, подобъект или один после последнего элемента в массиве? Хм... Это было мое предположение, но тогда у нас есть что:
целое число может быть преобразовано в тип anypointer. Кроме как уже указано, результат определяется реализацией, может быть неправильно выровнен, может не указывать на сущность ссылочного типа и может быть представлением ловушки.
поэтому я могу только интерпретировать его, что вышеуказанная программа четко определена, и стандарт C ожидает, что он напечатает "не равно", в то время как GCC действительно не подчиняется стандарту, но дает более интуитивный результат.
C++11, 5.10 / 1:
указатели одного типа (после преобразования указателей) можно сравнить за равенство. Два указателя одного типа равны, если и только если они оба null, оба указывают на одну и ту же функцию или оба представляют тот же адрес
Так что да, конкретное сравнение в порядке.
В общем случае попытка создать значение указателя, которое не является допустимым адресом, является неопределенным поведением - например, используя указатель арифметика идти до начала или после одного после конца массива-не говоря уже использовать их. Результат таких вещей, как (void*)23
определяется реализацией, поэтому, запрещая конкретное разрешение от реализации, это фактически неопределенное поведение для сравнения их тоже, так как реализация может определить, что результат является значением ловушки void*
.