- 1
- 2
- 3
- 4
- 5
std::vector<int> vec = { 1, 2, 3, 4 };
for (auto i = vec.size() - 1; i >= 0; i--) {
cout << i << ": " << vec[i] << endl;
}
cout << endl;
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+4
std::vector<int> vec = { 1, 2, 3, 4 };
for (auto i = vec.size() - 1; i >= 0; i--) {
cout << i << ": " << vec[i] << endl;
}
cout << endl;
Выстрел в ногу, заботливо прикрытый фиговым листочком «auto».
И только -Wextra заставляет нас прозреть:
хотя кто-то там на выступлении говорил аля "мы чет зря не сделали размеры контейнеров int'ами"
Давно уже пора выпилить unsigned, а лучше запретить по закону
Если вдруг захочется сёрвить кусок поискового индекса, замапленного в память, с 32-битной машины. Сейчас amd64 повсеместен, и проблема уже не так актуальна, как лет 15 назад.
Ну раз всё равно кусок - значит можно на той же машине поднять второй инстанс (а может и ещё несколько, если PAE работает и физической памяти хватает).
ДОС работал и на тех и на других.
Размер указателя был 32 бита и хранил он не линейный адрес, а запись из двух полей: сегмент + смещение. В упомянутых реализациях Си/C++ был даже нестандартный оператор :> для сборки указателя из сегмента и смещения.
В реальном режиме процессора (ДОС) эти 32 бита преобразовывались в 20-битный линейный адрес (сегмент тупо умножался на 16 и к нему прибавлялось смещение), а в защищённом (Windows) сегмент заменялся на базовый адрес из таблицы дескрипторов и к нему прибавлялось смещение, а результат мог занимать 32 бита. Но этот линейный адрес прятался где-то в глубинах процессора, а со стороны программ не был виден.
Так что к указателям было проще относиться как к «чёрному ящику».
Сегментная адресация применялась и на 32-битных машинах (PAE позволяла адресовать 64 гигабайта вместо 4), но уже считалась экзотикой.
*****
Так что в итоге делать с указателями в общем случае? У меня два варианта:
1. Считать указатель «чёрным ящиком», неким объектом фиксированного размера (не обязательно совпадающим с размером линейного указателя). Так было сделано в компиляторах для DOS и Windows 3.x.
2. Сделать указатели линейными, а в компилятор для машин с сегментной адресацией встроить транслятор, который будет преобразовывать указатели туда-сюда. Это негативно скажется на производительности.
К чему я это все. К тому, что к стандартному С++ это не имеет прямого отношения. Разработчики языка руководствуются двумя основными правилами: zero overhead abstractions and direct mapping to hardware. В следствии чего стандарт игнорирует сегментную адресацию, PAE и все такое. Есть абстрактное понятие storage, есть линейная адресация внутри него и есть типы, которые мапяться на регистры доступной разрядности. Я специально уточнил, что речь о стандарте языка(т.к. в примере кода стандартный контейней), которому всякие расширения или достандартные компиляторы не соответствуют просто по определению.
Это "unreal mode". Говнохак, очень популярный в игрушках.
>>dos4gw
ЕМНИП dos4gw использовал API "expanded memory" а не unreal mode.
>>В защищенном режиме в сегментные регистры помещаются селекторы дескрипторов
В 32 да, но мне кажется что в long mode уже нет. Там только pages.
>>абстрактное понятие storage, есть линейная адресация внутри него
Согласен. Но если мы пишем для tiny mode (все сегментные регистры указывают на начало, а размер памяти ограничен 64К) то у нас линейное пространство:)
А СёмаРеал - это бароп
а кто бароп - не знаю
голубой шильдик и оппозитный двигатель это уже диагноз так-то
Но прочитав свой коммент второй раз, теперь тоже вижу явный гомосексуальный контекст.
Кстати, а V-образный двигатель с развалом 180 градусов лучше оппозитного?
это не я, инфа 100%
А кресты можно за год выучить
Это не я.
За 20 дней же.
Селекторы это часть механизма защиты в защищенном режиме, они не должны никуда деться.
Я привел это в качестве примера вещей никак не связанных с С++. Ты понял, что я изначально писал конкретно про С++, про плюсовую memory model и типы завязанные на нее? Если да, то у тебя по прежнему есть возражения?
Вообще у меня есть такое наблюдение. Если задать вопрос джуну, то в ответ он выльет вот такой вот таз деталей реализации, про оффсеты и прерывания, баги MSVC, что у него скомпилилось, а что нет, без какой либо попытки ответить в терминах стандарта. Изначально вопрос стоял про стандартный вектор и рассматривать его в отрыве от стандарта, приплетая досовые компиляторы из 90х - дичайшее аматорство.
Пока что ты не привел ни одного пруфа своему пездежу кроме сомнительной ссылки на анскильный бложик васянов из тулы.
Ну чё ты такой сердитый человек-то, ну будьте людьми вы, ребята, я всегда вам говорю. Чего вы сразу начинаете?
> Важно, что модель памяти С++ ограничивает тебя только адресами, которые помещаются в size_t.
> Просто стандарт С++ не поддерживает никаких "других" платформ.
Выходит я был не прав, по поводу других платформ и непрерывной памяти. Признаю свою ошибку. Ты хамло, но спасибо, что обратил мое внимание на эти детали. Удивительно, как оно все это время ускользало... Пойду напьюсь теперь.
У меня для тебя дурные новости, чувак.
В середине восьмидесятых появилась страничная адресация, и теперь механизмы защиты есть и на уровне страницы тоже.
В long mode (aka x64) от сегментов практически избавились кроме парочки.
>>Если да, то у тебя по прежнему есть возражения?
Если ты почитаешь внимательнее, то увидишь что я с тобой не спорил.
Я совершенно согласен с тем, что С оперирует понятием "storage" и как должны вести себя указатели (в плане арифметики и разыменовывания) там тоже описано.
А как устроена памяти конкретной машины (есть там сегменты или еще что) -- это эквопенсиуально
Давай ладом. Селекторы отдельно, таблицы страниц отдельно. В сегментные регистры помещаются селекторы, указатель на таблицу в отдельный регистр. Прочитай то, что я написал еще раз.
> Если ты почитаешь внимательнее, то увидишь что я с тобой не спорил.
Конкретно в этом сообщении нет, но чуть выше разве не ты писал?
> Вообще никакой связи может не быть с размером адресного пространства и размером конкретного типа.
Так ты согласился с моим утверждением или оно все еще кажется недостаточно точным?
В том случае, который я описал, есть связь или нет никакой?
И? Как это противоречит тому, что я написал выше?
В 286 были только сегменты для защиты
В 386 и сегменты и страницы (только сегменты современные ОСы перестали для этой цели юзать)
в x64 и вовсе случился:
"In 64-bit mode, segmentation is generally (but not completely) disabled, creating a flat 64-bit linear-address space. The processor treats the segment base of CS, DS, ES, SS as zero, creating a linear address that is equal to the effective address. The FS and GS segments are exceptions. These segment registers (which hold the segment base) can be used as an additional base registers in linear address calculations. They facilitate addressing local data and certain operating system data structures."
Где тут защита-то?
>>В том случае, который я описал, есть связь или нет никакой?
Тот случай, это который?
Это
"Знаковый тип позволит адресовать только половину доступных адресов. Это и есть та причина, по которой размер стандартных контейнеров без знаковый.
"?
Ты пытаешься объяснить почему size_t в стандарте беззнаковый?
Участвуют сегментные регистры.
Да, но я не пытаюсь объяснить. Я уже объяснил, не только почему он беззнаковый, но и почему в векторе используется именно он. Казалось бы очевидная вещь, но не все понимают. Делюсь информацией, только и всего.
Вот да. Сегментация могла-бы в 32 mode юзаться для защиты памяти, но не юзается. А в 64 выпелена вовсе (точнее там как бы один большой сегмент размером со всю память).
Но размер сегмента это всего лишь одно из полей дескриптора. С тем что другие поля (DPL там всякий, да собственно и поле с указанием разрядности) юзаются я не спорю.
>не только почему он беззнаковый,
Что мешало сделать его знаковым, а работу с отрицательными значением объявить UB?
Я вот зацепился именно за это утверждение.
Допустим у меня sizeof(int) == 32, при этом максимально доступное адресное пространство 2^16.
Ну вот такая глупая система. Но что помешает мне ее создать?
действительно. Ну тогда
-32
+4
Давайте сразу оговоримся что адрес имел формат СЕГМЕНТ:СМЕЩЕНИЕ (оба по 16 бит) а как они мапились в реальные запросы (что выставлял на шину адреса проц) это отдельная песня.
Вот указатель мог быть ближним, и тогда он содержал только смещение.
При разыменовывании сегментный регистр никто не трогал, и потому если программист поменял значение сегментного регистра и забыл об этом, то указатель становился невалидным.
При адресной арифметике он просто перехлестывался через 64К делая невозможным хранение объектов большего размера.
Был far pointer, он имел еще и СЕГМЕНТ и перед разыменовыванием загружал его в регистр. Но адресная арифметика работала так же.
А был еще huge который умел менять сегментный регистр при адресной арифметике. Он был жутко тормозной, но позволял делать вид что он почти линейный.
При установке адреса на шину он "срезался" до 20 бит и потому можно было попасть в один и тот же кусок памяти разными способами. Говнокодеры полюбили этот прием, и когда адресную шину увеличили до 24 то оставили эмулятор старого поведения (см. Gate A20).
Товарищ внизу правильно говорит что с точки зрения стандарта это хуйня, но в стандарте не было понятия "far pointer".
> std::size_t can store the maximum size of a theoretically possible object of any type (including array).
> On many platforms (an exception is systems with segmented addressing) std::size_t can safely store the value of any non-member pointer, in which case it is synonymous with std::uintptr_t.
Такое может предложить только петух или питонист.
Тут нет совпадения. Просто стандарт С++ не поддерживает никаких "других" платформ. Это не значит, что их нет. Просто понятие адреса определено, без учета их особенностей.
P.S. Я тоже ламер.
а коли не пашет - сам иди на хуй
Потом оказывается что я захардкодил "c:\documents and settings\semareal" в семи местах
Вот ты пошутил, а мне с этим работать на работе приходится.
(не пхп)
На Dart пишете?
Да уже сдеанонили, походу. Они же тоже знают, что язык редкий и пути захардкоженные в проекте есть.
я могу изобрести копелятор в котором sizeof(short) == sizeof(long) == 8
а sizeof(size_t) == 64
Это тупо,нобудет же работать