Сообщество - Лига программистов C/C++

Лига программистов C/C++

69 постов 4 776 подписчиков

Популярные теги в сообществе:

1

О замене человека искусственным интеллектом

Недавно устроился на новую работу в связи с банкротством компании, в которой работал. Поскольку начинаю работать только в Сентябре, решил порешать задачки с leetcode, чтоб совсем мозги не закисали.

И вот одна из этих задачек. Даны два числа, представленные связными списками. Каждый элемент списка - это один знак этого числа. Причём в обратном порядке. Т.е. 721 будет выглядеть так: 1 -> 2 -> 7

Задача написать функцию, складывающую эти два числа. И дана уже заготовка кода.

/**

* Definition for singly-linked list.

* struct ListNode {

* int val;

* ListNode *next;

* ListNode() : val(0), next(nullptr) {}

* ListNode(int x) : val(x), next(nullptr) {}

* ListNode(int x, ListNode *next) : val(x), next(next) {}

* };

*/

class Solution {

public:

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {}

};

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

class Solution {

public:

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {

if((l1 != nullptr) || (l2 != nullptr) || (carry != 0) ) {

int tmp_result = ((l1 != nullptr) ? l1->val : 0) + ((l2 != nullptr) ? l2->val : 0) + carry;

if(tmp_result >= 10) {

carry = 1;

tmp_result -= 10;

} else {

carry = 0;

}

return new ListNode(tmp_result, addTwoNumbers((l1 != nullptr) ? l1->next : nullptr, (l2 != nullptr) ? l2->next : nullptr));

} else {

return nullptr;

}

}

private:

int carry = 0;

};

А причём тут ИИ, спросите вы? Да после того, как решил эту задачу, решил посмотреть, как её решит ИИ. А сделал он достаточно топорно, а именно так, как я хотел решать изначально.

class Solution {

public:

ListNode* addTwoNumbers(ListNode* _l1, ListNode* _l2) {

// Create a dummy head to simplify the list construction logic

ListNode* dummyHead = new ListNode(0);

ListNode* currentNode = dummyHead;

int carryValue = 0;

// Iterate while there are nodes in either list or a carry remains

while (_l1 != nullptr || _l2 != nullptr || carryValue != 0) {

// Get values from the current nodes, default to 0 if list is exhausted

int firstVal = (_l1 != nullptr) ? _l1->val : 0;

int secondVal = (_l2 != nullptr) ? _l2->val : 0;

// Calculate the sum of the digits and the current carry

int sumValue = firstVal + secondVal + carryValue;

carryValue = sumValue / 10;

// Create a new node with the digit part of the sum

currentNode->next = new ListNode(sumValue % 10);

currentNode = currentNode->next;

// Advance the pointers of the input lists

if (_l1 != nullptr) {

_l1 = _l1->next;

}

if (_l2 != nullptr) {

_l2 = _l2->next;

}

}

// Store the actual head of the result list

ListNode* resultHead = dummyHead->next;

// Free the dummy head memory to prevent memory leaks

delete dummyHead;

return resultHead;

}

};

На самом leetcode есть несколько решений к данной задаче. И нет ни одного решения с рекурсией. Да, я понимаю, многие не любят рекурсию и считают её антипаттерном, но тем не менее, задание тестовое, есть конструктор, кричащий: "Будь мужиком, заюзай рекурсию, б***ь!". По мне так, вариант с рекурсией выглядит проще и элегантнее.

Вывод напрашивается сам собой. Да, ИИ решит задачу. Но решит её так, чтоб она просто работала, т.е. на уровне индуса. А вот если надо проявить креативность, тут уже не так всё радужно. Хотя, зная, что это по сути языковая модель, а не интеллект, ожидать какой-то креативности от него не стоит.

P.S. Да, я знаю, что вместо (l1 != nullptr) можно было написать просто l1, но я предпочитаю именно такую запись в своём коде. Чтоб другие разрабы не искали каждый раз, что за переменные l1, l2, а уже понимали, что это какие-то указатели.

Показать полностью
12

Вы можете победить бинарный поиск

Иногда нам нужно найти значение в отсортированном массиве. Простейший алгоритм заключается в последовательном переборе значений, пока мы не встретим искомое значение или не достигнем конца массива. Такой алгоритм иногда называют линейным поиском. В C++ добиться такого же эффекта можно с помощью функции std::find.

Для больших массивов лучшего результата можно достичь с помощью бинарного поиска. Бинарный поиск является классическим алгоритмом, который эффективно находит целевое значение в отсортированном массиве, многократно деля интервал поиска пополам. Начиная со всего массива, он сравнивает целевое значение со средним элементом: если цель меньше, верхняя половина отбрасывается; если больше — отбрасывается нижняя. Этот процесс продолжается, пока цель не будет найдена или интервал не станет пустым. На больших наборах данных бинарный поиск значительно быстрее линейного. В C++ он реализован функцией std::binary_search, которая возвращает true или false в зависимости от существования элемента.

Популярный формат Roaring Bitmap использует массивы 16-битных целых чисел размером от 1 до 4096 элементов. Иногда нам приходится проверить, существует ли значение в этом массиве. Для этого мы используем бинарный поиск.

Я захотел создать более быстрый подход. У меня были две мысли:

  1. Практически все процессоры сегодня имеют инструкции для параллельной обработки данных (также называемая SIMD), которые могут проверять несколько значений за раз. И 64-битные ARM, и x64 процессоры (Intel/AMD) всегда поддерживают сравнение восьми 16-битных чисел с искомым значением используя всего одну инструкцию. Это подсказывает, что не стоит углубляться в бинарном поиске до блоков размером меньше восьми элементов. Кроме того, имеет смысл сравнивать шестнадцать элементов и больше.

  2. Бинарный поиск проверяет одно значение за раз. Однако, современные процессоры могут загружать и проверять более одного значения одновременно. Они обладают прекрасным параллелизмом на уровне памяти. Это говорит о том, что вместо бинарного поиска, стоит попробовать четверичный поиск: вместо того чтобы делить массив пополам, мы можем разделить их на четыре части. Конечный результат может потребовать чуть больше инструкций, но количество инструкций перестанет являться ограничивающим фактором.

Так я и создал алгоритм, который называю SIMD Quad. Это эффективный алгоритм поиска в отсортированных массивах с 16 битными беззнаковыми целыми числами, сочетающий четверичный интерполяционный поиск с SIMD (Single Instruction, Multiple Data). Алгоритм делит массив на блоки фиксированного размера по 16 элементов (возможно, за исключением последнего блока) и использует последний элемент каждого блока как интерполяционный ключ, чтобы быстро сузить область поиска до одного блока, а затем применяет SIMD-инструкции для одновременной проверки всех 16 элементов в этом блоке.

В основе лежит идея выполнения иерархического поиска: сначала используется интерполяционный поиск на более грубом уровне (по границам блоков), чтобы найти блок, содержащий целевое значение, а затем происходит переключение на SIMD для точной параллельной проверки внутри блока. Этот гибридный подход использует и сильные стороны алгоритмической оптимизации, так и аппаратного ускорения (SIMD проверяет несколько элементов за раз).

  1. Начальная проверка: если в массиве менее 16 элементов, выполняется простой линейный поиск

  2. Разбиение на блоки: массив делится на блоки по 16 последовательных элементов. Для массива размером cardinality существует num_blocks = cardinality / 16 полных блоков.

  3. Четверичный интерполяционный поиск: используем последний элемент каждого блока (на позициях 16-1, 32-1 и других) как ключи для интерполяции. Поиск выполняет четверичную (по основанию 4) интерполяцию, чтобы найти блок, в котором, вероятно, находится целевое значение. Это включает в себя сравнение цели с точками, делящими текущий диапазон поиска на четверти.

  4. Выбор блока: после сужения диапазона выбирается подходящий индекс блока lo на основе результатов интерполяции.

  5. SIMD-проверка: если найден верный блок, 16 элементов загружаются в SIMD-регистры (с использованием NEON на ARM или SSE2 на x64), после чего выполняются параллельные сравнения на равенство с целевым значением. Если найдено найдено хотя бы одно совпадание, возвращается true.

  6. Проверка остатка: для элементов, не вошедших в полные блоки (остаток) выполняется линейный поиск.

Каковы результаты этого? Я написал бенчмарк. Бенчмарк работает следующим образом: для каждого массива размером от 2 до 4096 элементов генерируется 100,000 сортированных массивов с 16-битными беззнаковыми целыми числами. Для каждого размера выполняется 10 миллионов запросов на принадлежность в «холодном» режиме (каждый запрос ищет в другом массиве, имитируя промахи кэша) и 10 миллионов запросов в «горячем» режиме (запросы сгруппированы по массивам, каждый массив обыскивается 100 раз подряд, имитируя попадания в кэш). Бенчмарк измеряет среднее время на один запрос для трёх алгоритмов: линейного поиска (std::find), бинарного поиска (std::binary_search) и нового алгоритма SIMD Quad.

Я использую две системы: Apple M4 с Apple LLVM и процессор Intel Emerald Rapids с GCC.

Во-первых, давайте сравним линейный и бинарный поиск.

Intel/GCC

Intel/GCC

Apple/LLVM

Apple/LLVM

Результат ясен. Бинарный поиск лучше чем линейный поиск, как только массивы становятся большими. Этого следовало ожидать.

На холодном кэше линейный поиск относительно хуже. Этого следует ожидать, потому что он получает доступ к большему количеству данных, вызывая больше ошибок кэша.

Мы установили, что бинарный поиск является чистым победителем по линейному поиску. Давайте теперь сравним с алгоритмом SIMD Quad.

Intel/GCC

Intel/GCC

Apple/LLVM

Apple/LLVM

Результаты заметно различаются между Intel и Apple. На Intel SIMD Quad более чем вдвое быстрее бинарного поиска на «горячем» кэше. На «холодном» кэше преимущества меньше. На платформе Apple ситуация обратная: именно на «холодном» кэше SIMD Quad оказывается более чем вдвое быстрее, тогда как на «горячем» кэше выигрыш более скромный.

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

SIMD-компонент алгоритма довольно прост: мы используем специализированные инструкции, которые сокращают объем работы. ПОэтому легко понять, почму это может ускорить процесс - меньше инструкций, меньше ветвлений.

Но как насчет «четверичной» (quad) части? Тогда я опробовал бинарную версию того же алгоритма. В нем присутствует та же SIMD-оптимизация, но я отказался от четверичного интерполяционного поиска и заменяю его стандартным бинарным поиском.

Intel/GCC

Intel/GCC

Apple/LLVM

Apple/LLVM

Говоря простыми словами, подход с четверичным поиском (quad) почти и не дает эффекта на Apple, однако на Intel он является неплохой оптимизацией для больших массивов в «холодном» режиме. Четверичный поиск лучше задействует параллелизм на уровне памяти на моём Intel-сервере.

Мой исходный код доступен.


Заключение: мои результаты говорят о том, что, хотя классический бинарный алгоритм из учебника — вполне достойный, его можно улучшить, причем ощутимо. Стандартные алгоритмы зачастую не проектировались под компьютеры с таким объемом параллелизма. Алгоритм SIMD Quad пытается задействовать и параллелизм на уровне памяти, и параллелизм на уровне данных. Более того, я подозреваю, что можно добиться даже большего, чем даёт мой алгоритм. Будьте креативнее!

❯ Исходный код

bool simd_quad(const uint16_t *carr, int32_t cardinality,
uint16_t pos) {
constexpr int32_t gap = 16;
if (cardinality < gap) {
for (int32_t j = 0; j < cardinality; j++) {
if (carr[j] == pos) return true;
}
return false;
}
int32_t num_blocks = cardinality / gap;
int32_t base = 0;
int32_t n = num_blocks;
while (n > 3) {
int32_t quarter = n >> 2;

int32_t k1 = carr[(base + quarter + 1) * gap - 1];
int32_t k2 = carr[(base + 2 * quarter + 1) * gap - 1];
int32_t k3 = carr[(base + 3 * quarter + 1) * gap - 1];

int32_t c1 = (k1 < pos);
int32_t c2 = (k2 < pos);
int32_t c3 = (k3 < pos);

base += (c1 + c2 + c3) * quarter;
n -= 3 * quarter;
}
while (n > 1) {
int32_t half = n >> 1;
base = (carr[(base + half + 1) * gap - 1] < pos)
? base + half : base;
n -= half;
}
int32_t lo = (carr[(base + 1) * gap - 1] < pos)
? base + 1 : base;

if (lo < num_blocks) {
const uint16_t *blk = carr + lo * gap;
#ifdef __ARM_NEON
uint16x8_t needle = vdupq_n_u16(pos);
uint16x8_t v0 = vld1q_u16(blk);
uint16x8_t v1 = vld1q_u16(blk + 8);
uint16x8_t hit = vorrq_u16(vceqq_u16(v0, needle),
vceqq_u16(v1, needle));
return vmaxvq_u16(hit) != 0;
#else
__m128i needle = _mm_set1_epi16((short)pos);
__m128i v0 = _mm_loadu_si128((const __m128i *)blk);
__m128i v1 = _mm_loadu_si128((const __m128i *)(blk + 8));
__m128i hit = _mm_or_si128(_mm_cmpeq_epi16(v0, needle),
_mm_cmpeq_epi16(v1, needle));
return _mm_movemask_epi8(hit) != 0;
#endif
}

for (int32_t j = num_blocks * gap; j < cardinality; j++) {
uint16_t v = carr[j];
if (v >= pos) return (v == pos);
}
return false;
}


Автор оригинальной статьи: Daniel Lemire

Автор перевода: DrArgentum

Написано при поддержке Timeweb Cloud

Больше интересных статей и новостей в нашем блоге на Хабре и телеграм-канале.


📚 Вам может быть интересно:

Реклама. ООО «ТАЙМВЭБ.КЛАУД», ИНН: 7810945525
Показать полностью 7
5

Языковые модели как компиляторы: Возможно ли?

Автор: Денис Аветисян


Исследование потенциала больших языковых моделей для прямой компиляции кода без традиционных этапов обработки.

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

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

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

Несмотря на значительные успехи в различных областях, возможность использования больших языковых моделей (LLM) в качестве полноценных компиляторов оставалась малоизученной. Данная работа, 'Exploring the Feasibility of End-to-End Large Language Model as a Compiler', посвящена исследованию потенциала LLM для прямой трансляции исходного кода в машинный, с акцентом на разработку датасета CompilerEval и фреймворка LaaC. Эксперименты показали, что LLM демонстрируют базовые способности к компиляции, однако текущий процент успешной компиляции остается низким. Возможно ли, путем оптимизации запросов, масштабирования моделей и внедрения методов рассуждения, создать LLM, способные генерировать высококачественный ассемблерный код и изменить парадигму компиляции?


Эволюция Компиляции: От Надежности к Гибкости

Традиционная компиляция, несмотря на свою надежность, представляет собой сложный и ресурсоемкий процесс. Растущий спрос на кроссплатформенность и поддержку специализированного оборудования требует адаптивных решений. Технологии искусственного интеллекта, в частности, большие языковые модели (LLM), предлагают принципиально новый подход к компиляции, способный упростить и ускорить разработку. Прозрачность алгоритмов – ключ к безопасному и эффективному программному обеспечению.

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

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

Возможность сквозной компиляции с использованием LLM демонстрирует потенциал для упрощения процесса разработки.

LLM как Компилятор: Новый Парадигма

Предлагаемый подход основан на непосредственном преобразовании исходного кода в машинный язык с использованием больших языковых моделей (LLM), минуя традиционные этапы компиляции. Разработанная платформа LaaC (LLM as a Compiler) является развитием данной идеи, ключевым компонентом которой является база знаний, содержащая информацию об исходных языках и наборах инструкций целевых архитектур. Несмотря на перспективность, текущие показатели успешной компиляции остаются относительно невысокими.

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

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

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

CompilerEval: Строгий Анализ Возможностей LLM

Для систематической оценки возможностей больших языковых моделей (LLM) в генерации ассемблерного кода разработана платформа CompilerEval, использующая специализированный набор данных CompilerEval Dataset. В рамках исследования была проведена оценка коэффициента успешной компиляции (Compilation Success Rate) для LLM, включая GPT-4o, Gemini-2.0, Claude-3.5 и Llama-3, на различных аппаратных архитектурах. Результаты демонстрируют зависимость эффективности от архитектуры и используемой модели.

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

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

Применение методов оптимизации запросов (Prompt Engineering) позволило улучшить показатели успешной компиляции. Так, для Claude-3.5-Sonnet наблюдалось увеличение на 7,5%, для GPT-4o с применением Chain-of-Thought – на 5%, а масштабирование Llama с Llama-70B до Llama-405B дало прирост в 1,55%.

Кроссплатформенность и Перспективы Будущего

Оценка продемонстрировала потенциал LLM для генерации кода для различных архитектур (x86, ARM, RISC-V), обеспечивая кроссплатформенную совместимость и автоматизацию разработки. Генерируемый код показал более высокие показатели корректности для ARM и RISC-V по сравнению с x86, что может быть связано с более стандартизированной природой этих архитектур.

Оценка производительности Claude-3.5-Sonnet при генерации кросс-платформенного ассемблерного кода демонстрирует его возможности в данной области.

Оценка производительности Claude-3.5-Sonnet при генерации кросс-платформенного ассемблерного кода демонстрирует его возможности в данной области.

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

Исследование демонстрирует, что большие языковые модели могут выступать в роли компиляторов, генерируя ассемблерный код непосредственно из высокоуровневых инструкций. Однако, успешность компиляции остаётся переменной величиной, требующей дальнейшей оптимизации и проработки. Это напоминает о высказывании Грейс Хоппер: “Лучший способ предсказать будущее — это создать его.”. В контексте LaaC Framework и необходимости повышения точности и эффективности компиляции, данная фраза подчеркивает активную роль исследователей в формировании будущего компиляционных технологий. Вместо пассивного ожидания прогресса, необходимо создавать инструменты и методы, способные преодолеть текущие ограничения и обеспечить надежную кросс-платформенную поддержку.

Что дальше?

Представленная работа демонстрирует, что границы между языковыми моделями и компиляторами становятся всё более размытыми. Однако, воспринимать это как немедленную замену традиционным системам было бы наивно. Достигнутые результаты – скорее, намек на возможность, чем окончательное решение. Ключевым вызовом остаётся не только повышение процента успешной компиляции, но и обеспечение предсказуемости, эффективности генерируемого кода и, что немаловажно, его переносимости между различными платформами. Необходимо признать, что текущие модели, по сути, "угадывают" компиляцию, а не выполняют её на основе строгой логики.

Дальнейшие исследования должны быть направлены на разработку более надёжных методов оценки и верификации сгенерированного кода, а также на создание инструментов для "отладки" логики языковых моделей, используемых в качестве компиляторов. Интересным направлением представляется изучение возможности интеграции существующих компиляционных технологий с LLM, создавая гибридные системы, сочетающие в себе сильные стороны обоих подходов. Ведь хаос — не враг, а зеркало архитектуры, которое отражает скрытые связи.

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


Оригинал статьи: denisavetisyan.com/yazykovye-modeli-kak-kompilyatory-vozmozhno-li-eto

Связаться с автором: linkedin.com/in/avetisyan

Показать полностью 5
13

Книга по C++, которую ты обязан прочитать в 2025 году

Я почему-то уверен, что она у тебя уже есть. Либо в списке литературы для самообразования, либо где-то среди скачанных pdf, а может, даже в печатном виде. Возможно, ты даже начинал её читать, но… работа, таски, собеседования… деньги вроде и так платят… и ты так и не осилил Мейерса "Эффективный и современный С++".

А ведь именно эта книга — ключ, который поможет тебе пробить потолок уровня middle и начать движение к senior.

Да, можно скачать список из 400 популярных вопросов, выучить их и бодро ответить на вопрос: «Расскажи про std::unique_ptr». А потом тебе прилетает дополнительный вопрос: «А как изменится размер std::unique_ptr при использовании пользовательского удалителя?» Иии… Я не буду додумывать твой уровень знаний. Попробуй сам ответить на этот вопрос и поставь себе оценку🙂
И это только один из примеров тонких нюансов, которые описаны в этой книге и которые реально спрашивают на собеседованиях.

Ещё одна сильная сторона книги: почти каждая фича современного C++ иллюстрируется примерами её использования в реальном проде. А это большая редкость для технической литературы.

Хватит откладывать эту книгу на «потом». Поставь цель на этот год и, наконец-то, найди время, чтобы прочитать 300 страниц "Эффективного и современного С++".

Книга по C++, которую ты обязан прочитать в 2025 году
Показать полностью 1
0

Скрытие программы из панели задач

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

Вот сам код: #include <windows.h>
#include <iostream>
#include <string>

int main()
{
int choice;
std::string programName;
HWND hwnd;

std::cout << "Choose an option:\n";
std::cout << "(1) Hide Window\n";
std::cout << "(2) Show Window\n";

std::cin >> choice;
std::cin.ignore();

switch (choice) {
case 1:
std::cout << "Enter the Window Name to hide: ";
std::getline(std::cin, programName);
hwnd = FindWindowA(NULL, programName.c_str());
if (hwnd == NULL) {
std::cout << "Program not found." << std::endl;
return 1;
}
ShowWindow(hwnd, SW_HIDE);
std::cout << "Window '" << programName << "' was hidden." << std::endl;
break;
case 2:
std::cout << "Enter the Window Name to show: ";
std::getline(std::cin, programName);
hwnd = FindWindowA(NULL, programName.c_str());
if (hwnd == NULL) {
std::cout << "Program not found." << std::endl;
return 1;
}
ShowWindow(hwnd, SW_SHOW);
std::cout << "Window '" << programName << "' is now visible." << std::endl;
break;
default:
std::cout << "Invalid option selected." << std::endl;
return 1;
}
return 0;
}

Показать полностью
1

Помогите с шифрованием на C++

Столкнулся сегодня с проблемой. Мне нужно сделать так, чтобы когда консоль была открыта, то у меня там отображался мой текст TriggerBot и AimAssist, а в памяти оно бы шифровалось. Пример: в консоли у меня есть "анимация" TriggerBot, но когда я сканирую память (к примеру с помощью Process Hacker или Cheat Engine), то в поиске строк в памяти вместо "TriggerBot", у меня бы там писалось к примеру hhajhfgdsghf==. Я сначала думал об VMP Protect, но решил, что он мне практически не поможет, поэтому решил обратиться к вам. Просьба помочь чем сможете, буду благодарен любому за помощь. Вот код:
#include <iostream>
#include <windows.h>

void fadeInText(const std::string& text) {
for (int i = 0; i <= 10; ++i) {
std::cout << "\r";
for (int j = 0; j < i; ++j) {
std::cout << text[j];
}
Sleep(50);
}
}

void fadeOutText(const std::string& text) {
for (int i = 10; i >= 0; --i) {
std::cout << "\r";
for (int j = 0; j < i; ++j) {
std::cout << text[j];
}
Sleep(50);
}
std::cout << "\r";
}

int main() {
std::string aimAssist = "AimAssist";
std::string triggerBot = "TriggerBot";

while (true) {
fadeInText(aimAssist);
Sleep(1000);
fadeOutText(aimAssist);

fadeInText(triggerBot);
Sleep(1000);
fadeOutText(triggerBot);
}

return 0;
}

Показать полностью
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества