Please open Telegram to view this post
VIEW IN TELEGRAM
В процессе разработки C++ приложений можно выделить несколько ключевых этапов: препроцессинг, компиляция, ассемблирование и линковка.
1. Препроцессинг:
На этом этапе выполняются инструкции препроцессора, такие как #include и #define. Препроцессор обрабатывает исходный код, заменяя макросы и объединяя файлы, что приводит к созданию промежуточного исходного кода.
2. Компиляция:
Программа преобразуется из высокого уровня (C++) в промежуточный язык - ассемблерный код. Компилятор проверяет синтаксис и семантику, генерируя ассемблерный код для каждой единицы трансляции.
3. Ассемблирование:
Ассемблер преобразует ассемблерный код в машинный код, результирующий в объектные файлы. Эти файлы содержат инструкции, которые может выполнять процессор, но еще не готовы к запуску как самостоятельные программы.
4. Линковка:
На завершающем этапе линковщик объединяет все объектные файлы, создавая исполняемый файл. Линковка также разрешает внешние ссылки между объектными файлами и библиотеками, обеспечивая корректное связывание функций и переменных.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Лямбда-выражения – это анонимные функции, которые могут быть определены прямо в месте их вызова. В C++ они позволяют создавать функции без необходимости явно объявлять их. Это особенно полезно для передачи функций в качестве аргументов другим функциям или использования в алгоритмах стандартной библиотеки.
Синтаксис лямбда-выражения выглядит следующим образом:
[capture](parameters) -> return_type {
// тело функции
}
Где:
-
capture
– захват переменных (можно указать, какие переменные из окружающего контекста будут доступны в лямбда-выражении);-
parameters
– параметры, которые будут переданы в лямбда-функцию;-
return_type
– (опционально) тип возвращаемого значения.Пример использования лямбда-выражения:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
// Вектор с числами
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Лямбда-выражение для вывода чисел
auto print = [](int n) {
std::cout << n << " ";
};
// Применяем лямбда-функцию для вывода всех чисел
std::for_each(numbers.begin(), numbers.end(), print);
std::cout << std::endl;
// Лямбда-выражение для суммирования
int sum = 0;
auto add_to_sum = [&sum](int n) { sum += n; };
// Применяем лямбда-функцию для суммирования всех чисел
std::for_each(numbers.begin(), numbers.end(), add_to_sum);
std::cout << "Сумма: " << sum << std::endl;
return 0;
}
В этом примере:
1. Определено лямбда-выражение
print
, которое принимает одно целое число и выводит его.2. Используется стандартный алгоритм
std::for_each
для применения лямбда-функции ко всем элементам вектора numbers
.3. Определено лямбда-выражение
add_to_sum
, которое захватывает переменную sum
по ссылке и суммирует все числа в векторе. Лямбда-выражения делают код более компактным и читаемым.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Шаблоны с несколькими параметрами в C++ позволяют создавать обобщенные функции и классы, которые могут работать с различными типами данных. Они обеспечивают гибкость и повторное использование кода, позволяя задавать несколько типов, а не ограничиваться одним.
Синтаксис шаблона функции с несколькими параметрами выглядит следующим образом:
template<typename T1, typename T2>
return_type function_name(T1 arg1, T2 arg2) {
// тело функции
}
Пример использования шаблона с несколькими параметрами:
#include <iostream>
#include <string>
// Шаблон функции для обмена значениями двух переменных
template<typename T1, typename T2>
void swap(T1& a, T2& b) {
T1 temp = a; // Временная переменная для хранения значения a
a = static_cast<T1>(b); // Присваиваем b значение a, приводя к нужному типу
b = static_cast<T2>(temp); // Присваиваем временную переменную значение b
}
int main() {
int x = 10;
double y = 20.5;
std::cout << "Перед обменом: x = " << x << ", y = " << y << std::endl;
// Вызов функции для обмена значениями
swap(x, y);
std::cout << "После обмена: x = " << x << ", y = " << y << std::endl;
return 0;
}
В этом примере:
1. Определена шаблонная функция
swap
, которая принимает два аргумента разных типов.2. Используются ссылки для изменения значений переменных
a
и b
.3. В функции происходит обмен значениями переменных с использованием временной переменной.
Шаблоны также можно использовать для классов. Пример шаблона класса:
#include <iostream>
// Шаблон класса для представления пары значений
template<typename T1, typename T2>
class Pair {
public:
T1 first; // Первое значение
T2 second; // Второе значение
Pair(T1 f, T2 s) : first(f), second(s) {} // Конструктор
void display() {
std::cout << "First: " << first << ", Second: " << second << std::endl;
}
};
int main() {
Pair<int, double> myPair(1, 2.5); // Создание объекта шаблона Pair
myPair.display(); // Вывод значений
return 0;
}
В этом примере:
1. Определён шаблон класса
Pair
, который хранит два значения разных типов.2. Конструктор принимает значения для инициализации.
3. Метод
display
выводит на экран хранимые значения.Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на концепции "объектов", которые представляют собой экземпляры классов. ООП включает в себя основные принципы:
1. Инкапсуляция — скрытие внутренней реализации объекта и предоставление интерфейса для взаимодействия.
2. Наследование — возможность создавать новые классы на основе существующих, что позволяет переиспользовать код.
3. Полиморфизм — возможность использовать объекты разных классов через один и тот же интерфейс, например, с помощью виртуальных функций.
Эти принципы способствуют структурированию кода, улучшению его удобства для поддержки и расширяемости.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Разница между статической и динамической линковкой в C++ заключается в том, как происходит связывание программного кода с библиотеками и как используются ресурсы во время выполнения программы.
Статическая линковка:
- Происходит во время компиляции. Все необходимые объектные файлы и библиотеки объединяются в один исполняемый файл.
Плюсы:
- Независимость от внешних библиотек: после компиляции программа не требует дополнительных библиотек для выполнения.
- Улучшенная производительность так как отсутствует overhead на загрузку библиотек во время выполнения.
Минусы:
- Увеличенный размер исполняемого файла из-за встраивания всех библиотек.
- Обновление библиотеки требует перекомпиляции программы.
Пример статической линковки:
// main.cpp
#include <iostream>
void function() {
std::cout << "Static Linking Example" << std::endl;
}
int main() {
function();
return 0;
}
Динамическая линковка:
- Происходит во время выполнения программы. Исполняемый файл использует внешние библиотеки, которые загружаются в память по мере необходимости.
Плюсы:
- Меньший размер исполняемого файла, так как библиотеки остаются отдельными.
- Возможность обновления библиотек без необходимости перекомпиляции программы.
Минусы:
- Зависимость от наличия необходимых библиотек на целевой системе.
- Возможные проблемы с совместимостью версий библиотек.
Пример динамической линковки:
// main.cpp
#include <iostream>
#include <dlfcn.h> // Библиотека для работы с динамическими библиотеками
int main() {
void* handle = dlopen("libmylibrary.so", RTLD_LAZY); // Загружаем библиотеку
if (!handle) {
std::cerr << "Ошибка загрузки библиотеки" << std::endl;
return 1;
}
void (*function)() = (void (*)())dlsym(handle, "function"); // Находим функцию
if (!function) {
std::cerr << "Ошибка нахождения функции" << std::endl;
dlclose(handle);
return 1;
}
function(); // Вызываем функцию из библиотеки
dlclose(handle); // Закрываем библиотеку
return 0;
}
Статическая и динамическая линковка представляют собой разные подходы к управлению зависимостями в C++, влияя на размер, производительность и гибкость программ.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
RAII (Resource Acquisition Is Initialization) — это идиома в C++, которая связывает управление ресурсами с временем жизни объектов. Основные принципы эффективного использования RAII:
1. Создание классов-оберток: Обернуть ресурсы, такие как динамическая память, файлы или сетевые соединения, в классы. Конструктор класса должен захватывать ресурс, а деструктор — освобождать его.
2. Исключения: RAII обеспечивает безопасность при работе с исключениями. Если в конструкторе происходит исключение, деструктор не будет вызван, что предотвращает утечки ресурсов.
3. Согласованность: Следует использовать RAII для всех управляемых ресурсов в программе, обеспечивая тем самым единый подход к управлению ресурсами.
Пример использования RAII для управления динамической памятью:
#include <iostream>
class Resource {
public:
Resource() {
// Захват ресурса
data = new int[10];
std::cout << "Resource acquired." << std::endl;
}
~Resource() {
// Освобождение ресурса
delete[] data;
std::cout << "Resource released." << std::endl;
}
private:
int* data;
};
void function() {
Resource res; // Ресурс будет автоматически освобожден при выходе из области видимости
// Выполнение операций с ресурсом
}
int main() {
function();
// После выхода из функции res будет освобожден
return 0;
}
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Конструкторы и деструкторы — специальные функции-члены класса в C++, управляющие жизненным циклом объектов.
Конструктор вызывается при создании объекта и используется для инициализации его данных. Он имеет то же имя, что и класс, и не имеет возвращаемого значения.
Деструктор вызывается при удалении объекта и используется для освобождения ресурсов. Имя деструктора совпадает с именем класса, но с префиксом тильда
~
, и также не имеет возвращаемого значения.Пример:
class MyClass {
public:
MyClass() {
// Конструктор: выделяем память или инициализируем данные
data = new int[10];
}
~MyClass() {
// Деструктор: освобождаем выделенную память
delete[] data;
}
private:
int* data;
};
В этом примере конструктор
MyClass()
выделяет память для массива, а деструктор ~MyClass()
освобождает эту память. Это обеспечивает корректное управление ресурсами и предотвращает утечки памяти.Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Специализация шаблонов в C++ позволяет определять особое поведение шаблонной функции или класса для конкретных типов данных. Это полезно, когда общая реализация шаблона не подходит для определенного типа, и требуется отдельная реализация.
Полная специализация — это определение шаблона для конкретного набора типов параметров. Например:
// Общий шаблон функции
template <typename T>
void print(const T& value) {
std::cout << value << std::endl;
}
// Полная специализация для типа int
template <>
void print<int>(const int& value) {
std::cout << "Integer: " << value << std::endl;
}
Частичная специализация применяется только к шаблонам классов и позволяет специализировать шаблон для определенных типов параметров, сохраняя другие параметры общими:
// Общий шаблон класса
template <typename T, typename U>
class MyClass { /*...*/ };
// Частичная специализация для случая, когда U — это int
template <typename T>
class MyClass<T, int> { /*...*/ };
В этом примере создается особая версия
MyClass
для всех типов T
, когда U
равно int
.Специализация шаблонов обеспечивает гибкость и оптимизацию кода, позволяя адаптировать шаблоны под специфические требования различных типов данных.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
RAII (Resource Acquisition Is Initialization) — идиома в C++, которая связывает время жизни ресурсов с временем жизни объектов. При использовании RAII ресурсы выделяются в конструкторе и освобождаются в деструкторе.
Это обеспечивает автоматическое управление ресурсами: при выходе объекта из области видимости его деструктор автоматически освобождает связанные ресурсы. Это особенно полезно для предотвращения утечек ресурсов, даже если возникли исключения.
Пример использования RAII для управления файловым дескриптором:
#include <fstream>
class FileWrapper {
public:
FileWrapper(const std::string& filename) {
file.open(filename);
// Проверяем, успешно ли открыт файл
if (!file.is_open()) {
throw std::runtime_error("Failed to open file");
}
}
~FileWrapper() {
// Деструктор: закрываем файл
file.close();
}
std::fstream& get() {
return file;
}
private:
std::fstream file;
};
// Использование класса
void processFile(const std::string& filename) {
FileWrapper fw(filename);
std::fstream& file = fw.get();
// Работа с файлом
}
В этом примере конструктор
FileWrapper
открывает файл, а деструктор автоматически закрывает его при выходе из области видимости объекта fw
. Это гарантирует корректное управление ресурсами без явного вызова close()
.Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Умные указатели (smart pointers) в C++ — это объекты, облегчающие управление динамической памятью. Они автоматически освобождают память, предотвращая утечки и обеспечивая безопасность.
Стандартная библиотека предлагает несколько типов умных указателей:
1. std::unique_ptr — обладает уникальным владением объектом. Объект удаляется при уничтожении указателя. Копирование запрещено, но возможна передача владения через перемещение.
#include <memory>
void func() {
std::unique_ptr<int> ptr(new int(5));
// Работа с ptr
} // Память автоматически освобождается здесь
2. std::shared_ptr — разделяет владение объектом между несколькими указателями. Ведется подсчет ссылок, и объект удаляется, когда последний указатель уничтожается.
#include <memory>
void func() {
std::shared_ptr<int> ptr1(new int(10));
{
std::shared_ptr<int> ptr2 = ptr1;
// Счетчик ссылок увеличился до 2
} // ptr2 выходит из области видимости, счетчик уменьшается до 1
} // Счетчик достигает 0, память освобождается
3. std::weak_ptr — слабая ссылка на объект, управляемый std::shared_ptr. Не увеличивает счетчик ссылок и используется для предотвращения циклических зависимостей.
#include <memory>
struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // Используем weak_ptr
};
Умные указатели помогают писать безопасный и эффективный код, автоматизируя управление ресурсами и следуя идиоме RAII.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Пользовательские классы исключений в C++ позволяют создавать специальные типы ошибок, которые можно точно обрабатывать при возникновении исключений.
Чтобы создать собственный класс исключения, наследуйте его от стандартного класса исключений, например, от
std::exception
или любого его потомка.Пример создания пользовательского исключения:
#include <exception>
#include <string>
class MyException : public std::exception {
public:
explicit MyException(const std::string& message)
: msg_(message) {}
virtual const char* what() const noexcept override {
return msg_.c_str(); // Возвращаем сообщение об ошибке
}
private:
std::string msg_; // Храним сообщение об ошибке
};
Использование пользовательского исключения:
void riskyFunction() {
// Некоторый код, который может вызвать ошибку
throw MyException("An error occurred"); // Бросаем наше исключение
}
int main() {
try {
riskyFunction();
} catch (const MyException& e) {
std::cout << "Caught MyException: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << "Caught std::exception: " << e.what() << std::endl;
}
return 0;
}
В этом примере класс
MyException
наследует от std::exception
и переопределяет метод what()
, чтобы вернуть пользовательское сообщение об ошибке. При вызове throw MyException("An error occurred")
исключение может быть перехвачено и обработано специфическим образом в блоке catch
.Создание пользовательских исключений помогает улучшить обработку ошибок и делает код более читаемым и поддерживаемым.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
Паттерн «Factory Method» позволяет создавать объекты через общий интерфейс, не указывая их конкретные классы. Суперкласс объявляет фабричный метод, а подклассы реализуют его, создавая нужные объекты.
Пример реализации:
// Абстрактный продукт
class Product {
public:
virtual void use() = 0;
virtual ~Product() = default;
};
// Конкретный продукт
class ConcreteProduct : public Product {
public:
void use() override {
// Реализация метода use для ConcreteProduct
}
};
// Абстрактный создатель
class Creator {
public:
virtual Product* factoryMethod() = 0;
void someOperation() {
Product* product = factoryMethod();
product->use();
delete product; // Освобождаем память
}
virtual ~Creator() = default;
};
// Конкретный создатель
class ConcreteCreator : public Creator {
public:
Product* factoryMethod() override {
return new ConcreteProduct();
}
};
В этом примере
Creator
определяет фабричный метод factoryMethod()
, который создает объекты типа Product
. Класс ConcreteCreator
переопределяет этот метод, создавая и возвращая экземпляр ConcreteProduct
. Клиентский код вызывает someOperation()
, не зная о конкретных классах продуктов. Это обеспечивает гибкость и упрощает добавление новых типов продуктов и создателей без изменения существующего кода.Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Процесс компиляции в C++ состоит из нескольких этапов:
1. Предварительная обработка (Preprocessing): Обрабатываются директивы препроцессора, такие как
#include
и #define
. Например:
#include <iostream> // Включение заголовочного файла iostream
#define MAX 100 // Определение константы MAX
2. Компиляция: Преобразование кода C++ в ассемблерный код.
3. Ассемблирование (Assembly): Перевод ассемблерного кода в объектный код (машинные инструкции).
4. Линковка (Linking): Объединение объектных файлов и библиотек в исполняемый файл.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Наследование в C++ позволяет создавать новые классы на основе существующих, используя их свойства и методы. Это способствует повторному использованию кода и иерархической организации.
Пример наследования:
class Animal {
public:
void eat() {
// Общий метод для всех животных
}
};
class Dog : public Animal {
public:
void bark() {
// Метод, специфичный для собак
}
};
В этом примере класс
Dog
наследует публичные члены класса Animal
. Это означает, что объекты Dog
могут использовать методы eat()
и bark()
.Типы наследования:
- Публичное наследование (public): публичные члены базы остаются публичными в производном классе.
- Защищённое наследование (protected): публичные и защищённые члены базы становятся защищёнными.
- Приватное наследование (private): все члены базы становятся приватными.
Наследование позволяет реализовать полиморфизм и использовать виртуальные функции для переопределения методов в производных классах.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤔1
Для реализации шаблонов с переменным числом параметров в C++ используются вариативные шаблоны (variadic templates). Они позволяют создавать функции и классы, работающие с произвольным числом аргументов.
Пример функции для вывода значений:
#include <iostream>
void print() {
// Базовый случай: нет аргументов
}
template<typename T, typename... Args>
void print(T first, Args... args) {
std::cout << first << " ";
print(args...); // Рекурсивный вызов с оставшимися аргументами
}
Использование:
print(1, 2.5, "текст");
// Вывод: 1 2.5 текст
В этом примере функция
print
принимает первый аргумент first
и пакет параметров Args...
. Она выводит first
и рекурсивно вызывает себя с оставшимися аргументами args...
.С появлением C++17 можно использовать fold expressions для упрощения кода:
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << std::endl; // Вывод всех аргументов
}
Это позволяет избежать рекурсии и сделать код более компактным.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
В C++ есть три уровня доступа для членов класса: public, protected и private.
- public: члены класса, помеченные как public, доступны из любого места в программе. Их можно вызвать или изменить из любого контекста.
- protected: члены, помеченные как protected, доступны внутри самого класса, а также в его потомках (классах-наследниках). Однако они недоступны вне этих классов.
- private: приватные члены доступны только внутри самого класса. Ни внешние функции, ни потомки не имеют к ним доступа.
Пример:
class Base {
public:
int publicMember; // Доступен всем
protected:
int protectedMember; // Доступен классу и наследникам
private:
int privateMember; // Доступен только внутри класса Base
};
class Derived : public Base {
public:
void accessMembers() {
publicMember = 1; // OK
protectedMember = 2; // OK
// privateMember = 3; // Ошибка: privateMember недоступен
}
};
void externalFunction() {
Base obj;
obj.publicMember = 1; // OK
// obj.protectedMember = 2; // Ошибка: protectedMember недоступен
// obj.privateMember = 3; // Ошибка: privateMember недоступен
}
Таким образом, выбор уровня доступа определяет, какие части кода могут использовать данные или функции класса.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Please open Telegram to view this post
VIEW IN TELEGRAM
1. Выбор эффективных алгоритмов и структур данных. Оптимальный алгоритм может значительно снизить время выполнения и потребление памяти.
2. Включение оптимизаций компилятора. Использование флагов компиляции, таких как
-O2
или -O3
, позволяет генерировать более эффективный машинный код.3. Избегание избыточного копирования. Передача объектов по
const
ссылке или использование std::move
для перемещения ресурсов.
void processData(const std::vector<int>& data); // Передача по константной ссылке
std::vector<int> data = getData();
processData(std::move(data)); // Перемещение данных
4. Использование эффективных контейнеров. Выбор подходящих контейнеров STL, таких как
std::vector
вместо std::list
для последовательного доступа.5. Уменьшение количества динамических выделений памяти. Предпочтение статического или стекового размещения объектов, использование пулов памяти.
6. Инлайн-функции. Использование ключевого слова
inline
для небольших часто вызываемых функций.7. Профилирование кода. Применение инструментов для выявления узких мест и точечной оптимизации.
8. Параллелизация. Использование многопоточности (std::thread) или SIMD-инструкций для распараллеливания вычислений.
9. Избежание виртуальных функций там, где это возможно. Виртуальные вызовы могут быть медленнее из-за динамической диспетчеризации.
10. Оптимизация работы с вводом-выводом. Буферизация операций ввода-вывода и минимизация обращений к диску.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Make — это утилита для автоматизации сборки проектов из исходного кода. Она использует Makefile — специальный файл, в котором описаны правила сборки и зависимости между файлами.
Основная идея Make: при сборке пересобираются только те части проекта, которые были изменены, что ускоряет процесс.
Простой пример Makefile для программы на C++:
# Компилятор и флаги компиляции
CXX = g++
CXXFLAGS = -Wall -std=c++17
# Исполняемый файл
TARGET = program
# Список объектов
OBJS = main.o utils.o
# Цель по умолчанию
all: $(TARGET)
# Правило сборки исполняемого файла
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)
# Правило для компиляции main.cpp
main.o: main.cpp utils.h
$(CXX) $(CXXFLAGS) -c main.cpp
# Правило для компиляции utils.cpp
utils.o: utils.cpp utils.h
$(CXX) $(CXXFLAGS) -c utils.cpp
# Очистка сгенерированных файлов
clean:
rm -f $(OBJS) $(TARGET)
В этом Makefile определены:
- Переменные:
CXX
, CXXFLAGS
, TARGET
, OBJS
.- Цели (targets):
all
, $(TARGET)
, main.o
, utils.o
, clean
.- Зависимости: например,
main.o
зависит от main.cpp
и utils.h
.- Команды: команды компиляции и сборки.
Чтобы использовать Makefile:
- Запуск сборки:
make
или make all
.- Очистка файлов:
make clean
.Make автоматически отслеживает временные метки файлов и пересобирает только те части, которые изменились, вместе с зависимостями.
Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5