Как стать автором
Обновить

Комментарии 62

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

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

Переслать ему что-ли Ваш комментарий. Сказать что актуальных проблем у него нет и пусть не волнуется понапрасну…
:)
Полностью поддерживаю. Я с ужасом жду того момента, когда мы будем переводить наш софт(в районе миллиона строк C/C++) на 64 бита. Видимо, нам попадутся всё ошибки из вашей статьи. За статью жирный плюс!
НЛО прилетело и опубликовало эту надпись здесь
вы его предупредили, что счет тоже будет 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.
Но эти же баги вероятнее всего вылезут при просто попытке модифицировать программу. Так что, ИМХО, статья больше относится к разряду «не делайте так ни-ког-да».

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

В любом случае, труд весьма приятный, особенно для облегчения понимая сути бяк для тех, кто ее (суть) еще не понимает
НЛО прилетело и опубликовало эту надпись здесь
Статья хороша для новичков, для себя ничего нового не нашёл. Все примеры из разряда тип стал больше и указатель тоже. Вообще за приведение указателя к инту по рукам бить надо. Ну и вообще в коде не должно быть никаких 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 большой, всё сразу не схватишь…
на яве пиши
предлагаю познакомиться с продолжением статьи: часть 2.
Аплодирую стоя! Вы Мужик! :)

P.S. Иллюстрации мега-зачетные!
большое спасибо, очень интересно, прочитал и всё понял
Зарегистрируйтесь на Хабре, чтобы оставить комментарий