|
Сравнение указателей может дать неожиданный результат
|
|
| zamabuvaraeu | Дата: Пятница, 17.04.2026, 19:54 | Сообщение # 1 |
|
Полковник
Группа: Друзья
Сообщений: 210
Статус: Offline
| Указатель ссылается на ячейку памяти, а разыменовать указатель — значит считать значение указываемой ячейки. Значением самого указателя является адрес ячейки памяти. Стандарт не оговаривает форму представления адресов памяти. Это очень важное замечание, поскольку разные архитектуры могут использовать разные модели адресации. Большинство современных архитектур использует линейное адресное пространство или аналогичное ему. Однако даже этот вопрос не оговаривается строго, поскольку адреса могут быть физическими или виртуальными. В некоторых архитектурах используется и вовсе нечисловое представление. Так, Symbolics Lisp Machine оперирует кортежами вида (object, offset) в качестве адресов.
Стандарт не оговаривает форму представления указателей, но оговаривает — в большей или меньшей степени — операции с ними.
Возьмём следующий пример: Код Dim a As Integer Dim b As Integer
Dim p As Integer Ptr = @a Dim q As Integer Ptr = @b + 1
Print Hex(p), Hex(q), p = q
Если мы скомпилируем этот код через GCC с уровнем оптимизации `-O 1` или выше и запустим программу, она напечатает следующее:
Обратите внимание, что указатели `p` и `q` ссылаются на один и тот же адрес. Однако результат сравнения `p = q` есть `False`, и это кажется странным. Разве два указателя на один и тот же адрес не должны быть равны?
Вот как стандарт определяет результат проверки двух указателей на равенство. Два указателя равны тогда и только тогда:
* оба являются нулевыми * либо указывают на один и тот же объект или функцию * либо указывают на позицию за последним элементом массива * либо один указатель ссылается на позицию за последним элементом массива, а другой — на начало другого массива, следующего сразу за первым в том же адресном пространстве
Указатель `p` получен из объекта `a`, а указатель `q` — из объекта `b`. Следовательно, по стандарту, эти указатели не могут быть равны, даже если их битовое представление совпадает.
|
| |
|
|
| haav | Дата: Пятница, 17.04.2026, 21:19 | Сообщение # 2 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Цитата zamabuvaraeu (  ) Если мы скомпилируем этот код через GCC с уровнем оптимизации `-O 1` или выше и запустим программу, она напечатает следующее: Такая фигня только с -O 1. С другими параметрами оптимизации адреса разные. По крайней мере на Linux x86-64
Ну и как доверять этим оптимизациям?
---------
Но если переписать пример так:
Код Dim p As Integer Ptr = @a + 1 Dim q As Integer Ptr = @b
Тогда указатели равны и да , сравнение приводит к false. Идиотизм! Получается на ровном месте можно получить кучу багов. Получается указатели нужно сравнивать только с помощью приведения к Integer. Я уж думал , что подобная ересь только на компиляторах вроде джавы (только там ссылки , а не указатели) , но компиль с++ получается тоже еще тот проказник.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| DarkDemon | Дата: Пятница, 17.04.2026, 22:59 | Сообщение # 3 |
|
Генерал-майор
Группа: Друзья
Сообщений: 328
Статус: Offline
| Цитата haav (  ) Ну и как доверять этим оптимизациям? Да вот и хрен знает))) Как это вообще тестить если в проге может внезапно появиться несколько созависимых багов. Типа мол если работает значит всё ok. Ну это очень так на тоненького...
|
| |
|
|
| haav | Дата: Суббота, 18.04.2026, 06:59 | Сообщение # 4 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Не , ну я понимаю ООП языки , там кругом объекты. В той же джаве , кроме нескольких примитивных типов , всё является объектами. Да и для примитивных типов тоже сделали обертки , чтобы они стали объектами . Поэтому важно , чтобы была возможность определять какому объекту принадлежит та или иная ссылка. Но GCC это же СИ , без малейшего намека на ООП. Здесь все определяется значениями , в том числе указатели. Но оказалось , что создатели GCC так не думают. А с другой стороны: че же одинаковый код без оптимизации ведет себя абсолютно по другому? Ведь принцип оптимизации - это увеличить скорость работы при тех же вводных. Но без оптимизации сравнение ведет себя логически и математически верно! Блин , есть же люди (те же разрабы GCC) , которые все время придумывают себе и другим проблем на ровном месте. Теперь , компиля с оптимизацией всегда надо писать: "моя программа собрана с оптимизацией , поэтому ничего не гарантировано" .
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| zamabuvaraeu | Дата: Суббота, 18.04.2026, 07:07 | Сообщение # 5 |
|
Полковник
Группа: Друзья
Сообщений: 210
Статус: Offline
| Код Ну и как доверять этим оптимизациям?
Всё совсем наоборот. По стандарту указатели на разные объекты не могут быть равны. Один указатель указыват на XXX, другой на YYY, очевидно что они не равны. Поэтому компилятор включает оптимизацию: зачем нам сравнивать битовое целочисленное представление (адреса), если нам уже известно, что указатели не равны. Вот и получается: адреса совпадают, но указатели не равны.Добавлено (18.04.2026, 07:18) --------------------------------------------- Например, возьмём x86 в реальном режиме. Вполне может быть что код программы хранится в одном сегменте, данные в другом, стэк в третьем. У объектов может быть адрес один и тот же, но храниться они будут в разных сегментах. Ну и как тут сравнивать? Сравнение даст ложноположительный результат. Поэтому в стандарте закреплено, что нужно смотреть не только на адреса, но и на «происхождение указателя».
|
| |
|
|
| haav | Дата: Суббота, 18.04.2026, 08:03 | Сообщение # 6 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Попахивает какими-то софизмами. И все бы было верно , если бы это было так:
Код Dim a As Integer Dim b As Integer
Dim p As Integer Ptr = @a Dim q As Integer Ptr = @b
Тогда да , нет смысла вычислять сравнение адресов. Но у нас то , один из адресов изменяется (то есть , это уже не тот же указатель , а изменившийся) и значит уже данная оптимизация приводит к некорректному результату.
Допустим , мы получили указатель для объекта , но потом решили изменить это и присвоили ему другой адрес (другой объект). У нас указатель теперь указывает на другой объект? Несомненно! А чем тогда эта запись:
Код Dim q As Integer Ptr = @b + 1
не является переназначением объекта? Ведь изначально это объект b , но мы сместили адрес и он уже указывает на что-то другое , но не на b. Но по логике оптимизирующего компилятора , это все еще объект b , и он не видит смысла вычислять значения адресов.
Еще раз , СИ не ООП язык и здесь нет объектов. В первую очередь важна математическая и логическая составляющая , а не фентезийная суть (объект не объект , тот ли это объект или не тот). Процессор не судит такими терминами как объекты , для него главное числа и их математика. А СИ всегда считался наиболее приближенным языком к машине (не считая ассемблера конечно). Кому в голову пришла "гениальная" идея изменить эту концепцию. А не происки ли это ревнивых фанатиков ООП языков? 
И да , я понимаю конечно , о чем ты говоришь. Чисто технически оно так и работает (так заложили логику работы компилятора при оптимизации) , но я считаю что данная оптимизация некорректна. Вообще , если оптимизация изменяет что-то кроме скорости работы , то я бы поискал другое слово для данного действа.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| zamabuvaraeu | Дата: Суббота, 18.04.2026, 08:39 | Сообщение # 7 |
|
Полковник
Группа: Друзья
Сообщений: 210
Статус: Offline
| Код Но у нас то , один из адресов изменяется (то есть , это уже не тот же указатель , а изменившийся)
Мы не можем гарантировать что сделав XXX+1, результат будет указывать на YYY. Адреса совпадут, но это не значит указатели равны, они всё равно находятся в разных сегментах.Добавлено (18.04.2026, 08:56) --------------------------------------------- Цитата Кому в голову пришла "гениальная" идея изменить эту концепцию. Наверное, это пришло в голову создателям x86 в реальном режиме. Где XXX хранятся в одном сегменте, и YYY хранятся в другом сегменте. Совпадение адресов XXX и YYY не гарантирует равенство, потому что они в разных сегментах лежат. Сколько бы мы ни прибавляли или вычитали из XXX, мы не получим YYY, как ни крути. Адреса совпадают, а сегменты — нет.
|
| |
|
|
| haav | Дата: Суббота, 18.04.2026, 08:57 | Сообщение # 8 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Цитата zamabuvaraeu (  ) Адреса совпадут, но это не значит указатели равны, они всё равно находятся в разных сегментах. Какие сегменты? У нас плоская модель памяти и адреса секций никогда не пересекаются. А кроме того , ты правильно сказал , мы не можем гарантировать. А раз не можем , то о какой нафиг оптимизации в данном месте может идти речь? Это уже не оптимизация , а кастрация какая-то. Это примерно то же самое , когда вместо того , чтобы проверить указатель на валидность мы оптимизируем код , удаляя проверку , выгадывая несколькими тактами. А потом начинаем бегать по коду , пытаясь понять , где же программа вылетает. В СИ указатель - это в первую очередь число , поэтому с ним надо работать как с числом , а не метафорическими смыслами.
Цитата Где XXX хранятся в одном сегменте, и YYY хранятся в другом сегменте Так все равно там указатель - это лишь часть адреса , с упором на нужный сегмент. Адрес неотделим от сегмента , поэтому изначально проверять только часть в принципе неверно. В плоской модели все адреса уникальные (принадлежат одному огромному сегменту) , поэтому здесь как раз есть смысл проверять адреса по значению.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| zamabuvaraeu | Дата: Суббота, 18.04.2026, 09:10 | Сообщение # 9 |
|
Полковник
Группа: Друзья
Сообщений: 210
Статус: Offline
| Компилятор обязан гарантировать одинаковое поведение кода строго соответствующего стандарту С на любых, даже самых упоротых платформ. Поэтому стандарт написан так, чтобы быть своего рода общим знаменателем всех возможных платформ (а не только для платформ с плоской моделью памяти). В стандарте нет требования только одного (линейного) адресного пространства. Нелинейное пространство — это таки норма для embedded процессоров, где программа хранится и выполняется из flash памяти, а данные хранятся в оперативной памяти. И есть вариант, когда переменная объявлена как неизменяемая — тогда она хранится в программной памяти, и указатель тоже показывает на программную память.Добавлено (18.04.2026, 09:18) --------------------------------------------- Цитата А кроме того , ты правильно сказал , мы не можем гарантировать Мы не можем гарантировать что они равны даже если адресы совпадают. Поэтому компилятор не сравнивает адреса, он сразу же выдаёт что они не равны.
|
| |
|
|
| haav | Дата: Суббота, 18.04.2026, 09:20 | Сообщение # 10 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Цитата Компилятор обязан гарантировать одинаковое поведение кода строго соответствующего стандарту С на любых, даже самых упоротых платформ. Он на одной платформе не способен гарантировать одинаковое выполнение кода , см. пример выше с разными опциями оптимизации. Все пытаются объять необъятное.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| haav | Дата: Суббота, 18.04.2026, 09:22 | Сообщение # 11 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Цитата zamabuvaraeu (  ) Мы не можем гарантировать что они равны даже если адресы совпадают. Поэтому компилятор не сравнивает адреса, он сразу же выдаёт что они не равны. Зашибись логика. Компилятор такой: фиг знает что за адреса , нифига делать не буду , сразу скажу , что это разные адреса.
Но тебе все равно спасибо , что доносишь до нас такие тонкости. Теперь я , если увижу некорректную работу своей программы , собранной с оптимизацией , лучше сразу соберу ее без оптимизации , а потом уже под настроение может быть буду разбираться , что же там еще нарукоблудили любители стандартов.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| zamabuvaraeu | Дата: Суббота, 18.04.2026, 09:29 | Сообщение # 12 |
|
Полковник
Группа: Друзья
Сообщений: 210
Статус: Offline
| Цитата Какие сегменты? У нас плоская модель памяти и адреса секций никогда не пересекаются Нет. Компилятор считает, что код написан по стандарту. А в стандарте ни о какой плоской модели памяти не упоминается.
|
| |
|
|
| DarkDemon | Дата: Воскресенье, 19.04.2026, 03:16 | Сообщение # 13 |
|
Генерал-майор
Группа: Друзья
Сообщений: 328
Статус: Offline
| Цитата zamabuvaraeu (  ) Указатель `p` получен из объекта `a`, а указатель `q` — из объекта `b`. Следовательно, по стандарту, эти указатели не могут быть равны, даже если их битовое представление совпадает. Только что мимолётно едва едва допедрил эту тонкую мысль. Т.е. рулит стандарт, а не логика))) Гениально!
Всё что пока понял, что это может создать огромные проблемсы разрабам кто не знает си. И тут вопрос, а на кой хер разрабу бейсика знать си? Ведь тогда можно писать на си и вероятно с не меньшей эффективностью.
А по поводу оптимизации. Все свои проги ВСЕГДА инженерю без оптимизации, видимо где-то на подсознаии ёкает, что может произойти дерьмо. И только когда уже прога готова, врубаю -O3. Обычно всё работает.
Но как мы видим с указателями надо прям аккуратно. Полагаю есть ещё дыры подобного характера. Неприятненько...
Т.е. это не та халява как многие внезапно посчитали и сделали выводы(на CF помню мне парни всё затирали по поводу того что я на старых версиях и что там тогда писал вспомните, что ПОДВЯЗКА к СТОРОННЕМУ инструменту выйдет БОКОМ). Но люди не смотрят на минусы, на идеологическую и архитектурную составляющую, когда перед глазами маячит лёгкий профит, халявка и расслабуха. Все хотят забить хрен на ручную архитектурную(и структурную) оптимизацию, просто врубить оптимизацию в опциях компиля - и "откинуться на спинку кресла". А разрабы средств разработки хотят перестать понимать(т.е. дословно - деградировать) что там асм делает внутри себя, устали видите ли - "трудна, долга".
Нам сейчас со всех щелей примерно тоже самое вливают про вайб-кодинг. От кодинга там правда одно название. Всё это можно назвать одним явлением - "эффективные менеджеры". Никак не переведутся.
Сообщение отредактировал DarkDemon - Воскресенье, 19.04.2026, 03:50 |
| |
|
|
| haav | Дата: Воскресенье, 19.04.2026, 08:22 | Сообщение # 14 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1474
Статус: Offline
| Цитата Компилятор считает, что код написан по стандарту Читаю статью: https://habr.com/ru/articles/893384/ . Оказывается компиляторы (даже именитые) , поддерживают эти стандарты в разной степени. А стандартов уже полдюжины с начала основания СИ.
И тут меня посетила мысль , а почему бы не взглянуть хоть одним глазком на данные стандарты (хотя бы на один из них). Забиваю поиск и офигеваю , что такие документы найти не так и просто. Наткнулся на сайт: https://webhamster.ru/mytetrashare/index/mtb0/16272523159p7689hnrj и вот там объяснили:
Цитата По странному стечению обстоятельств найти в Интернете стандарт на язык Си не так то просто. Похоже, что комитет ISO распространяет варианты этого стандарта за деньги, и сознательно скрывает информацию, где таковой стандарт можно получить в открытом виде. На этом же сайте можно найти , где же все таки можно раздобыть документы. Открываю стандарт С99. Итить твою... Это же полтыщи страниц , а в более новых стандаортах еще на 50% больше. И это для довольно примитивного языка с ~30 ключевыми словами. Закрыл стандарт
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| DarkDemon | Дата: Воскресенье, 19.04.2026, 09:25 | Сообщение # 15 |
|
Генерал-майор
Группа: Друзья
Сообщений: 328
Статус: Offline
| Цитата haav (  ) Но тебе все равно спасибо , что доносишь до нас такие тонкости. Замабувараев да, кстати крутой тестер, как он вообще всё это дерьмо находит))) Ну предполагаю что это был какой-то проект и там началось... Причём разрабы FB могут легко умыть руки, сказав - а это не наша область ответственности, но и на вопрос "чья" они, наверное внятно и не ответят. Но можно, наверное, скастить указатель в число и там уже сравнить, с этим то проблем надеюсь нет? И постоянно шпиговать код этими кастами, перегонять типы туда сюда. Получаем "правило Эскобара"...
Вроде понятно кто виноват и почему. Не понятно только что со всем этим делать, глобально.
Цитата zamabuvaraeu (  ) А в стандарте ни о какой плоской модели памяти не упоминается. Они каждые несколько лет переписывают свой стандарт. Думаю там у людей из 90-х накопилось много вопросов к ним. Представляю что бы мы жрали, если бы ГОСТ на тушёнку меняли так же... "Страшно! Очень страшно! Мы не знаем что это такое, если бы мы знали что это такое, мы не знаем что это такое!"Добавлено (19.04.2026, 09:38) ---------------------------------------------
Цитата haav (  ) На этом же сайте можно найти , где же все таки можно раздобыть документы. Открываю стандарт С99. Итить твою... Это же полтыщи страниц Стас, я помню смотрел стандарт бейсика 90 какого-то там года, вроде 92-го, скажу честно - довольно странное чтиво. Написанное, по ощущениям, просто свободным языком, в случайной последовательности, человеком с рассеянным склерозом. Называть это чем-то базо-образующим - трудно, работать с этими документами - можно бошкой двинуться... Не похоже чтобы кто-либо когда-либо пытался вообще систематизировать всю информацию, ощущение, что понабрали секретарш куриц какого-то соотвествтующего ведомства, которые этот документ сваяли, без понимания что пишут и зачем.
|
| |
|
|
|