Репутація українського ІТ. Пройти опитування Асоціації IT Ukraine
×Закрыть

Уроки разработки 64-битных приложений на языке Си/Си++

Курс состоит из 28 уроков, посвященных знакомству с 64-битными системами, вопросам сборки 64-битных приложений, методам поиска специфичных для 64-битного кода ошибок и оптимизации кода. Рассматриваются также вопросы, как оценка стоимости перехода на 64-битные системы и рациональность этого перехода.


www.viva64.com/ru/articles/x64-lessons

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Раз уж подняли столь древнюю тему, добавлю свой пример (примерно такой же древности). Пример на несколько обратный эффект — проблема только на 32-битной платформе :)

Код — триггер проблемы:

lseek(fd, -sizeof(buf), SEEK_END);

Пытаемся воспроизводить:


#include <stdio.h>
#include <fcntl.h>

int main()
{
  printf("%llx\n", (off_t)(-sizeof(int)));
  return 0;
}

Выдаёт 0xfffffffc.

Лечение очевидно, неочевидно натыкание на проблему.

Исходное обсуждение.

_LARGEFILE64_SOURCE, _FILE_OFFSET_BITS ?

off_t 64-битный. Во что и как стоят эти опции — мне пофиг (вообще, я в реальности не знаю, как сделать, чтобы там получилось 32 бита, это надо как-то особо постараться).

off_t 64-битный
#include <stdio.h>
#include <unistd.h>

int main()
{
    fprintf(stdout, "Size of off_t is %d\n", sizeof(off_t));
}

root@mikenfs:~/{}# gcc -m32 -D_FILE_OFFSET_BITS=32 fileofft.c -o fileofft
root@mikenfs:~/{}# ./fileofft
Size of off_t is 4
root@mikenfs:~/{}# gcc -m32 -D_FILE_OFFSET_BITS=64 fileofft.c -o fileofft
root@mikenfs:~/{}# ./fileofft
Size of off_t is 8

root@mikenfs:~/{}# uname -a
Linux mikenfs 3.13.0-73-generic #116-Ubuntu SMP Fri Dec 4 15:31:30 UTC 2015×86_64×86_64×86_64 GNU/Linux

Если в 2016 году ещё остались программы, которые считают, что off_t имеет размер 64 или 32 бита, то программеров нужно отправлять на переквалификацию.

off_t под вендой вообще не используется, есть стандартные size_t и ptrdiff_t и никаких проблем.

есть стандартные size_t и ptrdiff_t и никаких проблем.

Вы несёте чушь. Ознакомьтесь с CRT и WinAPI по поднятому вопросу.

Вообще справедливости ради нужно отделить мух от котлет, поскольку у нас обсуждение разработки 64-битных приложений. Одно дело разрядность аппаратной платформы, другое дело — файловая система. Если это FAT, то в любом случае размер файла не выходит за рамки 32-битного числа, независимо от x86 или x64 платформы. Если это допустим exFAT или NTFS, то допустмо работать с длинными файлами опять-таки независимо от платформы.

поскольку у нас обсуждение разработки 64-битных приложений

Ну, я с самого начала этой подветки пояснил, что это родственный случай (на ту же проблему переходов между 32- и 64-битными целыми), но не конверсия на 64-битную платформу. Поэтому тема обсуждения в целом здесь имеет только косвенное значение, а вот неожиданный ракурс проблемы 32/64 — прямое.

Если это FAT, то в любом случае размер файла не выходит за рамки 32-битного числа, независимо от x86 или x64 платформы.

Такой подход некорректен тем, что привязывает свойства интерфейса к конкретной FS, чего не делала даже Windows (имея в запасе, например, монтирование чего угодно с Novell или Unix по SMB, NFS и многим другим).
Описанные интерфейсы Windows и Unix никак не привязаны к конкретной FS (хотя указанная SetFilePointer, в отличие от SetFilePointerEx, оптимизирована на упрощение работы, когда смещение передаётся только как 32 бита).

(И ещё Вы почему-то тут не включаете exFAT в FAT. Мне такое деление непонятно — или называть каждый вариант FAT отдельно, или exFAT ничем тут не выделяется, кроме лицензирования.)

Твоё высказывание слишком туманно — с каким именно вариантом программиста надо отправлять на переквалификацию? Три варианта прочтения:
1) он думает, что всегда 32 бита
2) он думает, что всегда 64 бита
3) он думает, что 32 или 64 бита, в зависимости от чего-то

Если первое — согласен на 147%.

Если второе — я бы с удовольствием был таким программистом (тем более что я в начале этой части карьеры плотно сел на FreeBSD, которая сделала off_t 64-битным ещё в 2.0, и не представлял себе, что бывает иначе, пока не столкнулся с некоторыми странными системами вроде старой солярки). Но — увы, линуксы тут подкладывают свинью. Если я повторяю твой пример 1:1 на вполне себе современной системе (Ubuntu 14.04 LTS), и в 32-битке не задаю размер этого параметра, то получается:


$ gcc -o fileofft fileofft.c -m32
$ ./fileofft 
Size of off_t is 4

и тут, видимо, надо включить каким-то образом одну из названных тобой опций, чтобы оно стало цивилизованным. Хотя _LARGEFILE64_SOURCE тут не помогло. И неудивительно — почитал про него — оно добавляет off64_t и функции для него типа fseeko64, а не меняет off_t.

Если третий вариант — то вообще непонятно, к чему такое высказывание.

Если хочешь, чтобы я тебя понял — уточни, что имелось в виду.

И неудивительно — почитал про него — оно добавляет off64_t и функции для него типа fseeko64, а не меняет off_t.
Оно добавляет альтернативный 64 битовый интерфейс open64()/lseek64()/etc. Если в 32битовой системе нужна поддержка больших файлов, то объявляем _LARGEFILE64_SOURCE и используем его.
_FILE_OFFSET_BITS=64
Это делает прозрачным использование open()/lseek(). Хотя на самом деле вызываются аналоги open64()/lseek64(). Соответственно off_t равен off64_t. Попытка вдохнуть поддержку больших файлов в старый код, которая часто оборачивается проблемами подобными, что ты описал в начале треда.

Т.к. это POSIX расширения, то в ОС обе могут быть заранее предефайнены, поэтому в препроцессоре нужно анализировать их значения, либо при компиляции явно задавать. Это всё.

тем более что я в начале этой части карьеры плотно сел на FreeBSD, которая сделала off_t 64-битным ещё в 2.0, и не представлял себе, что бывает иначе, пока не столкнулся с некоторыми странными системами вроде старой солярки
QNX первая сделала time_t unsigned, проблемы выстреливают до сих пор, пару лет назад я даже правил git, ибо он плотно был уверен, что time_t signed. И такого валом.
Оно добавляет альтернативный 64 битовый интерфейс open64()/lseek64()/etc.

Спасибо, кэп :) Со вчера я это уже знаю (точнее, вспомнил заново, потому что давно не требовалось, и прочно забыл).

И такого валом.

Я надеюсь, ты не хочешь этим сказать, что фряшники неправы и что на самом деле их моральным долгом было заставить юзеров иметь ещё лет на 20 вперёд активный церебральный секс с разрядностью off_t и сопутствующих функций 8-\

Я надеюсь, ты не хочешь этим сказать, что фряшники неправы и что на самом деле их моральным долгом было заставить юзеров иметь ещё лет на 20 вперёд активный церебральный секс с разрядностью off_t и сопутствующих функций 8-\
Я хочу сказать, что без сопутствующих знаний — это бесполезно. Пример — я когда-то учавствовал в разработке Fido софта, писали тоссер и строили индексы. off_t торчала в структуре, которая сгружалась на диск, получили несовместимые между платформами файлы. Второй случай, чувак сделал всё правильно, но неправильно определил тип и выставил внаружу для записи на диск uint32_t offset, и вся поддержка 64 битных смещений коту под хвост.
#if (sizeof(off_t)==8)
    uint64_t offset;
#elif (sizeof(off_t)==4)
    # if defined(__LITTLEENDIAN__)
        uint32_t offset;
        uint32_t offset_hi;
    #elif defined (__BIGENDIAN__)
        uint32_t offset_hi;
        uint32_t offset;
    #else
        #error blah2
    #endif
#else
    #error blah
#endif

Как часто ты видешь в коде подобное? Вот и я о том же.

P.S. Пример с макросами не очень удачен — это для message passing между виртуальными машинами с разной разрядностью.

нужно отправлять на переквалификацию.
А как быть с вашей работой под рутом, в 2016ом году?
А как быть с вашей работой под рутом, в 2016ом году?
Мне можно, я взрослый.

Коллеги, «Си» ещё где нибуть используется кроме embedded ? (в смысле работы по Украине), по вакансиям очень глухо, даже разработка ядра никому не нужна сейчас ?

В разработке игр, в частности под телефоны.

Спасибо за ответ, но там как мне известно С++, а не Си, да и то под игры для мобильника часто используют Unity/C#, а «плюсы» всё же реже, хотя может вам виднее.
PS: Из-за опыта на Си мне как-то не лезит вся эта ООП-xрень вот и ищу где может Си ещё пригодится ...

Придется познать С++, с ним больше возможностей откроется !

Морда для JNI и вообще native API андроида — на С. Если вы посмотрите на интерфейс С библиотек (ну curl, например), то увидите кучу функций, где первым параметром идёт хэндл (curl.haxx.se/...libcurl/c/fileupload.html — видите там почти везде первым параметром curl). В С++ эти все функции были бы методами класса, с this вместо хендла. Это и есть ООП) А полиморфизм — он от лукавого) Это потом, осторожно и помолясь.
А частота использования лично для вас имеет очень малое значение. Вам важно, сколько платят и как легко устроиться, а это может не коррелировать с частотой.

ООП — это самая меньшая хрень, с которыми столкнётесь в проектах. Плюсы актуальны для 3D-графики, и везде где сложный рендеринг. Для разработки крупных приложений под современную винду всё равно придётся юзать дот нет, часть кода будет на C#, часть под управляемый C++, ну и часть на неуправляемом C++. Кроме того, основная часть логики скорее всего будет выноситься в скрипты. Можно конечно писать только на C# под Unity. Можно вообще на JS под WebGL.

Плюсы актуальны для 3D-графики, и везде где сложный рендеринг.
— Этож там математики туева-куча, плюс специфика С++ это вообще застрелится можно с такой работой ...

3D увязана с основами аналитической геометрии, матричное исчисление, кватернионы. Ну ещё немного кода выносится в шейдеры, вот там почти чистый C, без ООП :)

Ну вообще-то C99 оговаривает наличие типов intN_t, uintN_t и оговаривает их точный размер. Если нужны типы с количеством бит «не менее чем», то uint_leastN_t и int_leastN_t. А при использовании DWORD, u_int16_t, u_int8_t внутри вашего кода, а не для передачи параметров в системные функции, то кто ж вам всем доктор:)

To Mike Gorchak
ТА не совсем, по моему основная разница в юзании системных (а не языковых) типах данных, если ты юзаешь

те же — (int, long, short, etc) то разница действительно минимальная, но если везде по коду юзаются всякие (u_int16_t, u_int8_t, DWORD etc) то разница между системами становится значительней, хотя, по идее эти системные типы как раз и не должны меняться в размерности, при переходе на 64 бит.

Да вся разница только в long между линуксом (LP64) и виндовс (LLP64).

Авторы курса разрабатывают платную софтину для MS VS 2010, поэтому виндовая направленность не должна вызывать удивление: -)

Это точно, про VS2015 походу не знают. Про IA-64 упоминают, про ARM упоминаний там нет. Про модификатор __vectorcall и связанную тему — тоже не написали.

про VS2015 походу не знают

Да, машины времени им точно недостаёт.

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

Подписаться на комментарии