0 / 0 / 0
Регистрация: 10.04.2016
Сообщений: 9
FASM

Оптимизации при компиляции gcc в ассемблерный код

27.03.2019, 01:31. Показов 6182. Ответов 17
Метки fasm, gcc (Все метки)

Студворк — интернет-сервис помощи студентам
На лабораторную работу нам задали написать свой простейший транслятора си-подобного языка в ассемблерный код. Для этого я выбрал fasm и пока что доволен. Поскольку я совсем не силен в ассемблерном программировании, для написания кода подсматриваю нужные директивы на сайте godbolt, который позволяет посмотреть ассемблерный код, генерируемый разными компиляторами. Я заметил, что при использовании локальных переменных они помещаются в stack не подряд, а с выравниванием к нужному количеству байт. Например, при использовании кода:
C++
1
2
3
4
    char a = 2;
    short b = 4;
    short c = 5;
    int d = 6;
сгенерируется код
Assembler
1
2
3
4
  mov BYTE PTR [rbp-1], 2
  mov WORD PTR [rbp-4], 4
  mov WORD PTR [rbp-6], 5
  mov DWORD PTR [rbp-12], 6
Так же при активном "выделении" памяти на stack с помощью "sub esp, X" почему то используются множители 16.
Собственно мой вопрос: почему так делается, неужели так быстрее? Или это просто из-за простоты? При написании лабораторной, следует мне делать так же, или всё же использовать
Assembler
1
2
3
4
  mov BYTE PTR [rbp-1], 2
  mov WORD PTR [rbp-3], 4
  mov WORD PTR [rbp-5], 5
  mov DWORD PTR [rbp-9], 6
Отличия в сложности написания транслятора для двоих случаев, если они есть, меня не волнуют. Так же было бы интересно узнать о других таких приемах, которые не сложно добавить, потому что я не знаю, где их искать.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
27.03.2019, 01:31
Ответы с готовыми решениями:

Ошибка при компиляции в WinAvr GCC
WinAvr выдает ошибку при компиляции ни кто не вкурсе что с ней делать? в етих строках #if !defymed(__DOXYGEN__) static...

Ошибки в коде при компиляции с помощью GCC
Переписал код из книжки по C++. Переписал один в один, но компилятор выдает ошибки. Сам код // FunctionDemo - демонстрация...

GCC сгенерировал ассемблерный листинг программы. Не пойму, что делают некоторые его части
Здравия всем! Сгенерил листинг такого файла: int main(int argc, char** argv) { argc = 1; argv = '*'; return...

17
 Аватар для Kukuxumushu
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
27.03.2019, 01:48
Цитата Сообщение от mcmike Посмотреть сообщение
помещаются в stack не подряд, а с выравниванием к нужному количеству байт
Ну не просто так, конечно. Некоторые модели процессоров значительно медленнее работают с невыровненными по их размеру данными, а некоторые команды вообще отказываются с ними работать и выдают ошибку выравнивания.
Цитата Сообщение от mcmike Посмотреть сообщение
Так же при активном "выделении" памяти на stack с помощью "sub esp, X" почему то используются множители 16
Вообще, кадры стека принято выделять по его ширине, но в x64 там какие-то свои заморочки мною так до конца и не понятые (более опытные товарищи подскажут). По 16 байт обычно выравниваются данные xmm.
1
4179 / 1828 / 219
Регистрация: 06.10.2010
Сообщений: 4,117
27.03.2019, 12:59
Так же было бы интересно узнать о других таких приемах, которые не сложно добавить, потому что я не знаю, где их искать.
Ну например в x64 инструкции, которые оперируют 32-битными регистрами занимают меньше места и кажется даже выполняются быстрее, но это не точно.
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
28.03.2019, 14:25
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
Некоторые модели процессоров значительно медленнее работают с невыровненными по их размеру данными
Я бы даже сказал, не некоторые, а большинство. В современных процессорах достаточно не пересекать границу линии кэша (обычно это 64 байта, но может быть и 32), в более старых (типа Pentium 1 или AMD K8) – границу 4 или 8 байт. XMM-инструкции работают не так эффективно, если они не выравнены по 16 байтам.
Если интересует оптимизация, есть хороший мануал по этому делу: https://www.agner.org/optimize... sembly.pdf
Да и вообще тут много других интересных вещей можно найти

Цитата Сообщение от mcmike Посмотреть сообщение
Так же при активном "выделении" памяти на stack с помощью "sub esp, X" почему то используются множители 16.
Если я правильно понял вопрос, то стек должен быть выравнен по 16 байтам (по меньшей мере, перед вызовом других функции). Таковы требования соглашения о вызовах в x64.

Добавлено через 1 час 7 минут
Цитата Сообщение от murderer Посмотреть сообщение
Ну например в x64 инструкции, которые оперируют 32-битными регистрами занимают меньше места и кажется даже выполняются быстрее, но это не точно.
С регистрами в x64 вообще всё интересно.
По умолчанию для арифметики используются 32-битные регистры, а для адресации – 64-битные. Чтобы изменить разрядность, ставится префикс (REX-префикс и 67h соответственно). Поэтому инструкция mov eax,[rdx] будет на 2 байта короче, чем mov rax,[edx] (последняя будет одинаковой длины с mov ax,[edx])

Далее, при записи в 32-битный регистр (любой операцией, хоть mov, хоть add, хоть shr) обнуляется старшая часть соответствующего 64-битного регистра. Поэтому вместо movzx rax,eax (такой формы инструкции просто нет) делается mov eax,eax
1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
28.03.2019, 15:48
Цитата Сообщение от mcmike Посмотреть сообщение
а с выравниванием к нужному количеству байт.
вообще-то выравнивание включено у винды по-умолчанию,
и непонятно, почему она не ругается на твою строку mov BYTE PTR [rbp-1], 2

в доках интела vol.3A есть такое описание:

CR0 бит(18) разрешает флагу АС (EFLAGS бит 18) включать режим, в котором невыровненные обращения к памяти на уровне привилегий(3) вызывают исключение #АС (int-11h Alignment_Check). Проверки выравнивания НЕ действуют на секцию кода, а только на данные и стек. Исключение общей защиты (#GP) генерирует 128-битные типы данных, которые не выровнены по 16-байтовой границе.

Чтобы включить проверку выравнивания, должны выполняться следующие условия:
• Установлен флаг AM в регистре CR0 (бит-18).
• Установлен флаг AC в регистре EFLAGS (тоже бит-18).
• CPL равен 3 (защищенный режим или режим виртуального 8086).
Добавлено через 2 минуты
..сорян, это-же RBP поэтому видимо можно, а RSP нельзя.
хотя в любом случае стек получается невыровненным.
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
28.03.2019, 21:34
Цитата Сообщение от R71MT Посмотреть сообщение
вообще-то выравнивание включено у винды по-умолчанию
Что-то я не видел ни разу, чтобы Windows парил проги в user mode по поводу выравнивания. В kernel - да (и то неизвестно, каким образом там это сделано). Да и никаких битов AC там не выставлено.
1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
28.03.2019, 23:58
Цитата Сообщение от Jin X Посмотреть сообщение
Да и никаких битов AC там не выставлено.
..и точно сброшены у юзера,
хотя выравнивание в секции-данных даёт выигрыш в скорости,
т.к. требует на границах параграфа один/шинный цикл, а невыровненные данные - два цикла (можно попробовать снять профайл, при чтении/записи больших объёмов данных).
2
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
29.03.2019, 09:00
R71MT, угу.

Пруф, vol.1:
4.1.1 Alignment of Words, Doublewords, Quadwords, and Double Quadwords

Words, doublewords, and quadwords do not need to be aligned in memory on natural boundaries. The natural
boundaries for words, double words, and quadwords are even-numbered addresses, addresses evenly divisible by
four, and addresses evenly divisible by eight, respectively. However, to improve the performance of programs, data
structures (especially stacks) should be aligned on natural boundaries whenever possible. The reason for this is
that the processor requires two memory accesses to make an unaligned memory access; aligned accesses require
only one memory access.
A word or doubleword operand that crosses a 4-byte boundary or a quadword operand
that crosses an 8-byte boundary is considered unaligned and requires two separate memory bus cycles for access.
Some instructions that operate on double quadwords require memory operands to be aligned on a natural
boundary. These instructions generate a general-protection exception (#GP) if an unaligned operand is specified. A
natural boundary for a double quadword is any address evenly divisible by 16. Other instructions that operate on
double quadwords permit unaligned access (without generating a general-protection exception). However, additional
memory bus cycles are required to access unaligned data from memory.
2
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
30.03.2019, 09:41
Выравнивать данные меньше чем на 8-байт смысла нет, и вот почему..
Процессор и память связывает 64-битная шина, т.е. в любом случае минимальной порцией обмена является 8-байт. Но в большинстве случаях обмен происходит в пакетном режиме, с "Burst_Length" равным 8 (кол-во авто/повторов BL=8) - итого получаем 8*8=64 байт, которые сохраняются в кэш-памяти процессора как "64-byte cache_line". Таким образом, выставляемый процессором на шину адрес, всегда получается кратным 64 (младшие 6-бит обнуляются).

Шинный цикл - это число тактов от момента передачи адреса, до получения данных процессором (сумма таймингов памяти). На транспорт 64-байтного пакета расходуется всего 1 шинный-цикл, но только если начальный адрес пакета выровнен на 8-байтную границу! Посмотрим на скрин ниже:



Допустим, мы запросили выделенный жёлтым dword с адреса 013Eh..
Поскольку адрес процессора кратен 64, то он выставит на шину адрес 0100h, и в пакетном режиме считает в свой кэш весь/выделенный "морской волной" блок в диапазоне 0100-013F - на это уйдёт один шинный цикл. Но мы запросили dword, и старшее его слово вышло за пределы 64-байтной кэш-строки. Значит процессору придётся взять в свой кэш следующий блок с адреса 0140h, на что потребуется ещё один цикл-чтения.

А вот если-бы наш dword был выровнен на 8-байтную границу, то он в любом случае попал-бы в диапазон - или в первую кэш-линейку, или во-вторую. То-есть считался-бы за один шинный цикл.
2
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
30.03.2019, 12:13
Цитата Сообщение от R71MT Посмотреть сообщение
А вот если-бы наш dword был выровнен на 8-байтную границу, то он в любом случае попал-бы в диапазон - или в первую кэш-линейку, или во-вторую. То-есть считался-бы за один шинный цикл.
А зачем на 8 байт, когда тут можно на 4 байта выровнять? Т.е. 13Ch.
2
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
30.03.2019, 13:38
Цитата Сообщение от Jin X Посмотреть сообщение
А зачем на 8 байт
по-большому счёту, выравнивание привязывается к размеру регистров.
т.е. для х32 можно и на 4 выравнить, а для 8-байтных регистров х64, четвёрки уже не хватит.
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
30.03.2019, 13:58
Цитата Сообщение от R71MT Посмотреть сообщение
т.е. для х32 можно и на 4 выравнить, а для 8-байтных регистров х64, четвёрки уже не хватит.
А, ну это понятно. Просто ты сказал:
Цитата Сообщение от R71MT Посмотреть сообщение
Выравнивать данные меньше чем на 8-байт смысла нет
Для 16/32-байтных регистров (XMM, YMM) и 8 байт не хватит
1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
30.03.2019, 14:26
Да вообще, в наш век с многоядерными процессорами и тоннами кэша, предвыборкой и предсказанием переходов - проблемы оптимизации кода не существует в принципе. Это было актуально для вторых/третьих поколений машин, а сейчас уже за восьмое перевалил. Это бородатые преподы никак не могут расстаться со-своим прошлым, и тянут туда-же студней.
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
30.03.2019, 16:38
R71MT, не соглашусь. Нюансов оптимизации полно и сейчас. Начиная от sub ecx,1 + jnz vs loop, продолжая выравниванием (оно всё же имеет значение) и заканчивая выбором инструкций для отдельных вещей (тут много примеров). Перестановка не всегда поможет, элементарно:
Assembler
1
2
3
4
5
add eax,ebx
add eax,ecx
add eax,edx
add eax,esi
add eax,edi
современный "умный" процессор не заменит на более быстрый вариант:
Assembler
1
2
3
4
5
add ecx,edx
add esi,edi
add eax,ebx
add ecx,esi
add eax,ecx
1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
31.03.2019, 10:38
Я хочу сказать, что современный процессор даже не будет пытаться что-то заменить в примере выше (этим должен заниматься компилятор) - процессор выполнит в 2-раза больше простых инструкций всего за один такт, поскольку сейчас у него не парочка, а 8..16 исполнительных блоков ALU (не считая скалярных, см.Skylake), ..плюс 48 штук у GPU (см.Gen11). Причём работают эти блоки - параллельно!

Если коротко, то современное "Оut-оf-Оrder" ядро является гибридным и включает в себя блоки как "внеочередного", так и "спекулятивного" исполнения команд. Процессор не исполняет инструкции последовательно, и пока занимается текущей, в фоне обрабатывает сразу и последующие (из кэша-инструкций).

Если у этих/последующих готовы все операнды, то такие инструкций внеочереди отправляются в свободный порт (см.скрин ниже), который связан с исполнительным блоком ALU/FPU. Если-же операнды не готовы, то инструкция откладывается до лучших времён и ждёт, пока до неё дойдёт указатель CS:EIP.

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

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

Оптимизация кода была актуальна для процессоров до i486 (Am5) включительно. Дальше, микроархитектура мутировала - к имеющийся CISC добавили RISC c основным нововведением "Декодер инструкций" (до 486 его не было). Именно декодер разбивает наши инструкции на упрощённые RISC, которые можно выполнять параллельно сразу на нескольких ALU. Теперь у процессора есть своя/внутренняя система команд, не имеющая ничего общего с теми инструкциями, которые поступают извне.

Поэтому сколько-бы мы не потратили сил на оптимизацию кода в своих программах, ядро процессора всё-равно проигнорирует наш план, т.к. работает по своим/аппаратным правилам, которые мы не в силах изменить. (хотя вмешаться в эти правила конечно-же можно, если добраться до "MicroOps-ROM", где хранятся RISC-инструкции). Единственным условием оптимизации в современных процессорах является код, который использует смешанные с FPU инструкции, т.к. исполняющие блоки внутри ядра у них разные - для ALU свои, для FPU свои и они по-большей части простаивают.
Миниатюры
Оптимизации при компиляции gcc в ассемблерный код  
2
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6787 / 2029 / 236
Регистрация: 14.12.2014
Сообщений: 4,260
Записей в блоге: 12
31.03.2019, 21:24
Цитата Сообщение от R71MT Посмотреть сообщение
Поэтому сколько-бы мы не потратили сил на оптимизацию кода в своих программах, ядро процессора всё-равно проигнорирует наш план, т.к. работает по своим/аппаратным правилам, которые мы не в силах изменить.
А зачем нам это менять? Нам надо просто пользоваться этим
1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
01.04.2019, 11:37
помоему на хабре когда-то была статья, где чел путешествовал внутрь процика..
вот цитата от из этой статьи:
Ниже приводится путь,
который совершает инструкция в современном процессоре (2008-2013).

Вы – инструкция в программе, и эта программа запускается..
Вы терпеливо ждете, пока IP начнет указывать на вас для последующей обработки. Когда IP указывает примерно за 4кб до вашего расположения (или за 1500 инструкций), вы перемещаетесь в кэш инструкций. Загрузка в кэш занимает некоторое время, но это не страшно, так как вы ещё нескоро будете запущены. Эта предзагрузка (prefetch) является частью первого этапа конвейера.

Тем временем IP указывает всё ближе и ближе к вам, и, когда он начинает указывать за 24 инструкции до вас, вы и пять соседних команд отправляетесь в очередь инструкций (instruction queue).

Этот процессор имеет четыре декодера, которые могут вмещать одну сложную команду и до трёх простых. Так случилось, что вы сложная инструкция и были декодированы в четыре микрооперации.

Декодирование – это многоуровневый процесс. Часть декодирования включает в себя анализ на предмет требуемых вами данных и вероятность перехода в какое-то новое место. Декодер зафиксировал потребность в дополнительных данных. Без вашего участия, где-то на другом конце компьютера, нужные вам данные начинают загрузку в кэш данных.

Ваши четыре микрооперации подходят к таблице псевдонимов регистров. Вы объявляете с какого адреса памяти вы читаете (например, это оказывается fs:[eax+18h]), и чип транслирует его во временный адрес для ваших микроопераций. Ваши микрооперации входят в ROB, откуда, при первой же возможности, двигаются в резервацию.



Резервация содержит инструкции, готовые к исполнению. Ваша третья микрооперация немедленно подхватывается нулевым портом исполнения. Вам не известно, почему она была выбрана первой, но её уже нет. Через несколько тактов, ваша первая микрооперация устремляется в пятый порт - блок загрузки адресов. Оставшиеся микрооперации ждут, пока различные порты подхватывают другие микрооперации. Они ждут, пока пятый порт загружает данные из кэша данных во временные слоты памяти.

Другие инструкции приходят и уходят, в то время как ваши микрооперации ждут своего друга, пока тот загружает нужные данные. Хорошо, что этот процессор знает как обрабатывать их внеочерёдно!

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

По пути обратно через ворота, микрооперации передают свои билеты с временными адресами. Микрооперации собираются и объединяются, и вы вновь, как инструкция, чувствуете себя единым целым. Процессор вручает вам ваш результат и вежливо направляет к выходу.

Через дверь с пометкой "Отставка" стоит короткая очередь. Вы встаете в очередь и обнаруживаете, что вы стоите за той же инструкцией, за которой и заходили. Вы даже стоите в том же порядке. Получается, что OOO-ядро действительно знает своё дело!

Со стороны выглядит так, что каждая выходящая из процессора команда выходит по одной, точно в таком же порядке, в каком IP указывал на них.
Кстати, начиная с архитектуры "NetBurst" (Pentium IV) был введён локальный "TraceCache", куда сбрасывались уже сдекодированные инструкции. Если некая x86-команда исполнялась повторно, декодеру не нужно было снова преобразовывать её в свой/внутренний код, и он подхватывался из кэша. От скорости работы декодера полностью зависят ALU/FPU, но почему-то сейчас от кэша-трассы отказались, хотя сам декодер остался.

1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6180 / 2416 / 400
Регистрация: 29.07.2014
Сообщений: 3,151
Записей в блоге: 4
01.04.2019, 11:46
последний рисунок - это микро/архитектура NetBurst четвёртого пенька.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.04.2019, 11:46
Помогаю со студенческими работами здесь

При компиляции на Dev прога пашет, а на gcc нет.
Эта программа удаляет среднюю цифру числа. #include<stdio.h> main() { int k=1; long long int l; long long int m=0; long long...

Ошибки при компиляции ClanLib с помощью GCC(MinGW) 4.6.2
компилирую ClanLib с помощью GCC(MinGW) 4.6.2 делаю configure --enable-clanDisplay --enable-clanGL --enable-clanGL1 --enable-clanGUI...

Ошибки при компиляции ассемблерной программы с помощью gcc
простая программка в качестве примера .data st: .ascii "hello Gas\n" .set len = . - st .text .global main ...

При компиляции с помощью gcc или llvm, происходит ошибка и они требуют амперсанд
Всем привет! Столкнулся с таким кодом: int a,i; ... scanf("%d",a); ...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

Новые блоги и статьи
Blazor и контроллер сервопривода IoT Meadow Maple
Wired 11.07.2025
Я решил разобраться, как можно соединить современные веб-технологии с миром "железа". Интересная комбинация получилась из Blazor в качестве веб-интерфейса и микроконтроллера Meadow с его веб-сервером. . .
Генерация OpenQASM из кода Q#
EggHead 10.07.2025
Летом 2024-го я начал эксперименты с библиотекой Q# Bridge, и знаете что? Она оказалась просто находкой для тех, кто работает на стыке разных квантовых экосистем. Основная фишка этой библиотеки -. . .
Изучаем новый шаблон ИИ-чата .NET AI Chat Web App
stackOverflow 10.07.2025
В . NET появилось интересное обновление - новый шаблон ИИ-чата под названием . NET AI Chat Web App. Когда я впервые наткнулся на анонс этого шаблона, то сразу понял, что Microsoft наконец-то. . .
Результаты исследования от команды ARP (июль 2025 г.)
Programma_Boinc 10.07.2025
Результаты исследования от команды ARP (июль 2025 г. ) Африканский проект по дождям (ARP) World Community Grid снова запущен! Мы рады поделиться обновленной информацией о нашем прогрессе с осени. . .
Angular vs Svelte - что лучше?
Reangularity 09.07.2025
Сегодня рынок разделился на несколько четких категорий: тяжеловесы корпоративного уровня (Angular), гибкие универсалы (React), прогрессивные решения (Vue) и новая волна компилируемых фреймворков. . .
Code First и Database First в Entity Framework
UnmanagedCoder 09.07.2025
Entity Framework дает нам свободу выбора, предлагая как Code First, так и Database First подходы. Но эта свобода порождает вечный вопрос — какой подход выбрать? Entity Framework — это. . .
Как использовать Bluetooth-модуль HC-05 с Arduino
Wired 08.07.2025
Bluetooth - это технология, созданная чтобы заменить кабельные соединения. Обычно ее используют для связи небольших устройств: мобильных телефонов, ноутбуков, наушников и т. д. Работает она на частоте. . .
Руководство по структурам данных Python
AI_Generated 08.07.2025
Я отчетливо помню свои первые серьезные проекты на Python - я писал код, он работал, заказчики были относительно довольны. Но однажды мой наставник, взглянув на мою реализацию поиска по огромному. . .
Тестирование энергоэффективности и скорости вычислений видеокарт в BOINC проектах
Programma_Boinc 08.07.2025
Тестирование энергоэффективности и скорости вычислений видеокарт в BOINC проектах Опубликовано: 07. 07. 2025 Рубрика: Uncategorized Автор: AlexA Статья размещается на сайте с разрешения. . .
Раскрываем внутренние механики Android с помощью контекста и манифеста
mobDevWorks 07.07.2025
Каждый Android-разработчик сталкивается с Context и манифестом буквально в первый день работы. Но много ли мы задумываемся о том, что скрывается за этими обыденными элементами? Я, честно говоря,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru