Pull to refresh

Comments 62

Ничего не понял, но чувствую что статья крутая
Здравствуй, сферический в вакууме хабравчанин 2010 года!
Изумительная статья.
Объяснено все так, что поймет даже начинающий программист.
О большей половине ошибок я и не догадывался до сегодняшнего дня.
UFO just landed and posted this here
Си++ — программисты с мегабайтами унаследованного кода улыбаются.

У нас вот тут клиент с программным комплексом, состоящим из проектов, собираемых с помощью VC1, VC2, VC3, VC4,…! И всего в сумме 5 миллионов строк кода. И он думает, как бы из всего этого сделать проект для VS2010 и собрать 64-битную версию.

Переслать ему что-ли Ваш комментарий. Сказать что актуальных проблем у него нет и пусть не волнуется понапрасну…
:)
Полностью поддерживаю. Я с ужасом жду того момента, когда мы будем переводить наш софт(в районе миллиона строк C/C++) на 64 бита. Видимо, нам попадутся всё ошибки из вашей статьи. За статью жирный плюс!
UFO just landed and posted this here
вы его предупредили, что счет тоже будет 64-битный?
т.е. int не будет 64 битным или будет? Я что-то думал, что int/uint тоже будут на 64 бита, хоть это иногда и не нужно. А может можно директиву компилятору какую написать вроде #define true false, в смысле #typedef int int64?
PS: Сам на Си только курсовики и лабы делал.
В Win64 тип int точно не будет 64-битным. В unix мире существуют системы, где int 64-битный. Но и там размер int в основном равен 32-битам. Вообще размеры типов зависят от используемой модели данных.

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

Вы возможно имели в виду
typedef int64 int?
Если да, то это будет неработоспособно по ряду причин.
Знаете, а это первая нормальная статья о переходе на 64 бита…

Прошлые были полным ойёйёй.
да ну. За большую часть ошибок, надо отрывать руки. Вообще. На корню.

Далее, не говорится что для размеров стоит использовать size_t;

Далее, не говориться что на нормальных архитектурах

while(curr_pos - buffer < length && *curr_pos != '\r')
  curr_pos++;


приведет к сегфолу, ибо верить что ты имеешь доступ к любой памяти, это крайне наивно!
Да, за большинство из этих ошибок надо отрывать много чего, однако есть тонны кода с такими ошибками, который работает и перестанет это делать будучи собранным под х64

Речь ведь не о характеристике давно уволенных кодеров, а про «что с этим делать?», имхо тоже статья лучшая из этой тематики на данный момент
Гм, вы понимаете почему код, который я привел не будет работать?

Далее. если человек путает sizeof(int) и sizeof(int*) то это уже повод задуматься.
Почему? :)

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

А то по вашему получается, что в С++ теперь нельзя разыменовывать указатели без какого-то непонятного шаманства.
фикус в том, что есть нормальные архитектуры, где доступ к не выровненной памяти не возможен. В интеле он просто сильно медленее!
Даже с учетом этого приведенный код будет работать, потому что char выравнивается на 1 байт. И даже если бы там были не char, а что-то еще оно бы все равно работало, потому как типы обычно выравниваются на размер типа.
char *a = malloc(24 * sizeof(char));

при sizeof(char) == 1 мы получаем аж целых 24 байта. В случае powerpc мы сможем обратиться только к адрессам выравненым по смещению кратному dword. И данный код работать не будет, увы.
т.е. в PowerPC нет понятия «байт» с точки зрения процесора?

я имею в виду, что на х86 в ассемблере можно писать

mov bl, byte ptr[address]    ; выравнивание на 1 байт
mov bx, word ptr[address]    ; выравнивание на 2 байта
mov ebx, dword ptr[address]  ; выравнивание на 4 байта 


до х64 ассемблера я не дожил, но думаю там тоже как-то так… а как в power pc?

з.ы. кстати, конструкция с циклом при компилировании в х86 вообще должна превратиться в что-то вроде «repne scasb»
интел и вообще x86 я не считаю за приличную архитектуру. Популярную, да. Но не приличную!
Так расскажите, все-таки, как вы конец строки в PowerPC ищите?
надо использовать нормальные функции. например length и strstr или strchr

Если надо циклам, то я бы переводил строку к long и делал бы логические операции с несколькими шаблонами ;)
да, смещал потом просто указатель на long. Обычно dword это и есть sizeof(long)
Да… без нормальных функций это некрасиво выглядит… Впрочем, возможно, оно быстрее работает, чем у Intel, интеловский ассемблер действительно перегружен командами…
Согласись, что мемантически использовать функцие для этого более правильно. Легче читать.

+ ты не завязан на архитектуру.

А смысл статьи про перенос: делайте абстракции и используйте функции. И по возможности используйте готовые функции. И не используйте знания, какие-то. Они могут измениться.
Естественно :)

Я бы также добавил про смысл: избегайте массивов в си стиле и непонятных операций с типами. В с++ есть STL. Всякие malloc и free в коде использоваться не должны, разве что в таких вещах, как Small Object Allocator, но таких мест в программе обычно очень мало, да и ошибки там отлавливаются очень быстро.
А если я пишу на чистом Си?
Чем более низкоуровневый язык, тем больше нужно знать о целевом железе, это нормально
не нормально когда пишут не зная, увы
Для аллокаторов есть Boost, который вот-вот в стандарт включат, так что кроме случаев хардкорной оптимизации в программе вообще не должно быть прямой работы с malloc (тем более что в рамках плюсов все равно лучше использовать new)
Нету в бусте Small Object Allocator, он в Loki :)

Вообще, я аллокаторы для примера привел… Вообще все «низкоуровневые» функции имеет смысл скрывать за абстракциями, только долго это, кода лишнего требует… Поясню, под «низкоуровневыми» я понимаю все, что платформо-зависимо, в т.ч. API.
Если char это 1 байт (что, и на powerpc благо так), то проблем с выравниванием не будет. Они проявляются только для более длинных типов, там попытка лезть в невыровненную память приведет к Bus Error.

Т.е. ваш пример все-таки работать будет, а вот
int* aligned = new int[2];
*(reinterpret_cast<int*>(reinterpret_cast<char*>(aligned) + 1)) = 0xDEADBEEF;

упадет
>> Далее. если человек путает sizeof(int) и sizeof(int*) то это уже повод задуматься.

Прошу пояснить, о чем Вы? Быть может Вы какую то опечатку/ошибку в статье заметили? А то не понятно о чем речь.
Я про программиста, для которого это писалось.
Чего только люди не придумают, лишь бы языками со строгой типизацией не пользоваться…
Спасибо, очень интересно. Жду продолжения.

P.S. И это при том, что я питонщик… :-)
15 пример реален, подтверждаю ;)
много проблем делалают функции с переменным количеством аргументов и 0 в конце вместо (Some_Object*)0 вроде бы у вас в статьях это уже было.
портирование становится еще интерестней, когда необходимо поддерживать несколько платформ, к примеру x86_64 linux и win64
от майкрософта бывают также сказочные приветы из прошлого. пример ничего общего с 64битностью не имеет, но все же: переносил приложение из VS6 на 2008 и atol начал возвращать LONG_MAX, хотя в VS6 могло вернуть значение до ULONG_MAX
Статья хорошая, но, по большому-то счету, к х64 имеет ну очень опосредованное отношение.
Да, эти баги стопудово вылезут при попытке компилять в х64.
Но эти же баги вероятнее всего вылезут при просто попытке модифицировать программу. Так что, ИМХО, статья больше относится к разряду «не делайте так ни-ког-да».

Ну и да, вырвать руки по самую задницу за такие вот реализации надо создателям вот этого.

В любом случае, труд весьма приятный, особенно для облегчения понимая сути бяк для тех, кто ее (суть) еще не понимает
UFO just landed and posted this here
Статья хороша для новичков, для себя ничего нового не нашёл. Все примеры из разряда тип стал больше и указатель тоже. Вообще за приведение указателя к инту по рукам бить надо. Ну и вообще в коде не должно быть никаких 9 и прочей магии.
Сорри, прочитал, блин, все, кроме последнего. На 15й я и не обратил внимание, спасибо. Вот это действительно интересная штука, хотя у вас тоже некорректно, ибо однажды приведя целое число к любому вещественному типу потом их сравнивать посредством == нельзя. Точнее может и можно, но лучше так не делать.
А давайте разведем холивар про строгое сравнивание вещественных?
Еще как можно их сравнивать, только очень, очень осторожно и с пониманием дела
Если 14 из 15 примеров о том как записать указатель в инт, или передеть в функцию long long int вместо инта, то понимания дела у целевой аудитории статьи, к сожалению, нет.
Согласен.
Собственно, повторюсь про отрывание рук по самую задницу, потому что из плеч такие золотые руки расти не могут =)
Статья хорошая. Все понятно и просто написано. Классные иллюстрации.

Как раз сейчас занимаюсь переводом 32 в 64. Конечно объемы не миллионы строк, а чуть меньше 10 тысяч…
Предупрежден, значит вооружен.
Статья понравилась. В ближайшее время вряд ли будет необходимость переводить наш код в 64-битный вариант, но лучше знать заранее.
УРРА!!! Я снова вижу эти тексты, спасибо Андрей2008!
Ой, что-то в статье ничего не говорится про опенмп. Может и там есть различного рода подводные камни?
А VivaMP продается плохо. Из-за этого рассказывать про 64-битные камни намного полезней.
Спасибо за кристально честный ответ. Но, кстати, тему многопоточности в современном мире можно неплохо раскрывать и дальше. А 64-бит все одно на самом деле: указатели, магические числа, а остальное или явные баги и undefined behavior.
Единственный вопрос который вызывает эта статья — «Ну и зачем весь этот геморрой в приложении, которое замечательно работает на 32 битах?!»
Для того, чтобы дать приложению возможность использовать более 3Гб памяти. Да, это далеко не всем приложениям надо, но если уж надо…
Может, это я такой, что предупреждён, вооружён и использую static_cast<size_t>(-1LL) как специальное значение беззнакового целого?

А может, примеры родом из «детского прошлого» середины 90-х годов, когда у большинства проггеров буквально кружилась голова от «плоской» модели памяти…
P.S. Кружилась в «хорошем» смысле — выделяй сколько хочешь памяти, если вдруг надо оптимизировать на ассемблере — регистры ds и es мучить уже не надо…
numeric_limits<size_t>::max() как-то поправильнее будет :)
Спасибо. STL большой, всё сразу не схватишь…
Аплодирую стоя! Вы Мужик! :)

P.S. Иллюстрации мега-зачетные!
большое спасибо, очень интересно, прочитал и всё понял
Sign up to leave a comment.