==
сравнивает опорное значение объектов, тогда как equals()
метод присутствует в java.lang.String
класса сравнивает содержимое String
объекта (к другому объекту). Стандарт С не допускает этого.
6.5.6 Аддитивные операторы (выделение мое)
8 Когда выражение, имеющее целочисленный тип, добавляется или вычитается из указателя, результат имеет тип операнда указателя. Если операнд-указатель указывает на элемент объекта массива , и массив достаточно велик, результат указывает на смещение элемента от исходного элемента, так что различие индексов полученного и исходного массива элементы равны целочисленному выражению. Другими словами, если выражение P указывает на i-й элемент объекта массива, выражения (P) + N (эквивалентно, N + (P)) и (P) -N (где N имеет значение n) указывают соответственно i + n-му и in-му элементам массива, если они существуют. Кроме того, если выражение P указывает на последний элемент объекта массива, выражение (P) +1 указывает один за последним элементом объекта массива, а если выражение Q указывает на один последний элемент последнего элемента массива, выражение (Q) -1 указывает на последний элемент объекта массива. Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, при оценке не должно быть переполнения; в противном случае поведение не определено . Если результат указывает на один последний элемент массива, он не должен использоваться в качестве операнда оцениваемого унарного оператора *.
blockquote>Для целей вышеизложенного указатель на отдельный объект рассматривается как указывающий на массив из 1 элемента.
Теперь
((uint8_t*)0)
не указывает на элемент объекта массива. Просто потому, что указатель, содержащий нулевое значение указателя, не указывает на какой-либо объект . Сказано в:6.3.2.3 Указатели
3 Если константа нулевого указателя преобразуется в тип указателя, результирующий указатель, называемый нулевым указателем, гарантированно сравнивается с указателем на любой объект или функцию.
blockquote>Так что вы не можете делать арифметику с ним. Предупреждение оправдано, потому что, как упоминается во втором выделенном предложении, мы имеем дело с неопределенным поведением.
Не обманывайтесь тем фактом, что макрос
offsetof
возможно реализован подобным образом. Стандартная библиотека не связана с ограничениями, накладываемыми на пользовательские программы. Это может использовать более глубокие знания. Но делать это в нашем коде не очень хорошо определено.
Небольшое разъяснение по этой теме.
Прежде всего, это неопределенное поведение в соответствии со стандартом C по причинам, указанным StoryTeller:
Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или одного после последнего элемента объекта массива оценка не должна вызывать переполнения; В противном случае, поведение не определено.
blockquote>Поскольку литерал с нулевой константой, преобразованный в любой тип указателя, затухает в константу нулевого указателя, которая не указывает на какую-либо непрерывную область памяти, поведение не определено.
Однако , выполнение арифметических операций с нулевыми указателями для извлечения смещений не ново, реализация C макроса
offsetof
использует его:#define offsetof(st, m) ((size_t)&(((st *)0)->m))
И делает такая же арифметическая мода на указатели также часто встречается:
int *end = (int *)0 + array_size;
Эта строка практически совпадает с записью:
int *end = (int *)(sizeof(int) * array_size);
Я считаю, что вычисление смещения определяется реализацией, как компилятор [115 ] «Мог» разыменовать такие указатели, чтобы получить фактическое смещение памяти, что, конечно, очень маловероятно, но все же возможно.
Также обратите внимание, что это предупреждение для арифметики нулевого указателя относится к Clang 6.0. GCC не запускает его даже с
-fsanitize=undefined
.