Різниця між способами включення файлів у C ++

Де б я не запитав, як додати клас або бібліотеку до мого проекту C ++, кожен каже, що я повинен створити файл .h, використовувати директиви препроцесора, оголосити в ньому прототипи функцій і створити новий файл .cpp для запису функцій в і, нарешті, включити файл .h у наш main.cpp. Але коли я просто додаю cpp/h до моїх вихідних файлів, він також працює. Отже, що таке точка створення .cpp і .h, якщо я можу написати весь мій код в одному файлі і включити його в моєму main.cpp?

1
@molbdnilo якщо ви знаєте відповідь, будь ласка, напишіть її, якщо ви не бажаєте не писати безглузді речі
додано Автор Sam379, джерело
@molbdnilo якщо ви знаєте відповідь, будь ласка, напишіть її, якщо ви не бажаєте не писати безглузді речі
додано Автор Sam379, джерело
@molbdnilo якщо ви знаєте відповідь, будь ласка, напишіть її, якщо ви не бажаєте не писати безглузді речі
додано Автор Sam379, джерело
простими словами, краще керування кодами.
додано Автор Shamim Hafiz, джерело
Коли ваш код зросте, ви побачите, чому, молодий коник.
додано Автор molbdnilo, джерело
Коли ваш код зросте, ви побачите, чому, молодий коник.
додано Автор molbdnilo, джерело
Коли ваш код зросте, ви побачите, чому, молодий коник.
додано Автор molbdnilo, джерело
Коли ваш код зросте, ви побачите, чому, молодий коник.
додано Автор molbdnilo, джерело
Чи намагалися ви заздалегідь знайти відповіді на це питання? читати мене
додано Автор Andrew_CS, джерело

11 Відповіді

Якщо ви пишете маленькі іграшкові програми, це може бути більше зусиль, ніж варто розбити все в модулях, які логічно розділені. Я підтримую кілька проектів /hacks на моїх жорстких дисках, де я роблю тестування та експерименти, і вони, як правило, є лише одним великим файлом.

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

  • Код написаний для людей, а не для машин. Порушення систем у багатьох невеликих файлах подібне до написання есе з багатьма пунктами, кожен з яких складається з декількох (але не надто багато) пропозицій. Написання цілого есе в 1000 слів як єдине послання може бути можливим, але читати буде дуже боляче. Крім того, набагато простіше знайти те, що ви шукаєте, у тисячах невеликих файлів, організованих належним чином, ніж в одному масивному файлі.

  • Розбиття файлів, особливо файлів заголовків, якомога менше, але не меншого, може значно покращити компіляцію.

  • Розбиття модулів може допомогти роз'єднати розрізнені системи та визначити, де існують штучні муфти.

Загалом, суть у тому, що це робить речі простішими , і це завжди добре.

2
додано

Якщо ви пишете маленькі іграшкові програми, це може бути більше зусиль, ніж варто розбити все в модулях, які логічно розділені. Я підтримую кілька проектів /hacks на моїх жорстких дисках, де я роблю тестування та експерименти, і вони, як правило, є лише одним великим файлом.

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

  • Код написаний для людей, а не для машин. Порушення систем у багатьох невеликих файлах подібне до написання есе з багатьма пунктами, кожен з яких складається з декількох (але не надто багато) пропозицій. Написання цілого есе в 1000 слів як єдине послання може бути можливим, але читати буде дуже боляче. Крім того, набагато простіше знайти те, що ви шукаєте, у тисячах невеликих файлів, організованих належним чином, ніж в одному масивному файлі.

  • Розбиття файлів, особливо файлів заголовків, якомога менше, але не меншого, може значно покращити компіляцію.

  • Розбиття модулів може допомогти роз'єднати розрізнені системи та визначити, де існують штучні муфти.

Загалом, суть у тому, що це робить речі простішими , і це завжди добре.

2
додано

Маючи чітке, логічне розмежування між різними "одиницями" вашої програми, це допомагає тримати її акуратною та акуратною. Це допомагає зрозуміти, куди йде, що використовує, і взагалі "як все це збігається". Якщо ви просто включите все в одну велику крапку коду, дуже легко "не правильно розділяти речі", тому раптом змінна в A.cpp використовується в B.cpp, а не оголошується змінною як "extern" в Ah, або ще краще, має функцію доступу до неї з будь-якого місця, але фактична змінна "захищена" всередині B.cpp, так що ніхто інший не може його використовувати.

Техніка "утримання речей окремо" називається інкапсуляцією - ви бачите тільки "біти" файлу, який насправді піддається заголовку. Таким чином, я, як другий програміст у вашому проекті, знаю, які біти я можу змінити (якщо він працює так само) всередині A.cpp - все, що не в A.h, буде "справедливою грою". Те, що знаходиться в A.h, треба більш ретельно розглядати, оскільки це означає, що щось за межами A.cpp може використовувати його, і ми повинні дивитися, де/як це використовується, перш ніж він може бути змінений.

Це робить велику різницю у великих проектах. Якщо у вас є 100 або 200 рядків коду, ви можете буквально запам'ятати всі рядки коду, і якщо ви щось зміните на рядку 150-160, ви легко зможете пам'ятати, що одна і та ж змінна використовується також у рядках 172 і 189, тому ви потрібно змінити і там. Коли ваш проект довжиною 2000 рядків, одна людина може керуватися знанням більшості всього відразу. Якщо ви написали всі 100k рядків, ви, ймовірно, можете керувати ним. Якщо у вас є 1M рядки коду, більшість з яких хтось написав, вам потрібна хороша структура, щоб мати можливість змінювати речі, не закінчуючи безладом, який не працює. Звичайно, ви ніколи не будете працювати над проектом лінії 5K, якщо ви не покажете, що ви розумієте, як це має бути зроблено в першу чергу.

На жаль, це трохи довго, але загальна ідея полягає в наступному: якщо ви тримаєте його чистим і акуратним, у вас є кращий спосіб роботи, який в кінцевому підсумку приведе до кращого програмного забезпечення.

2
додано
Добре ... але моє питання трохи відрізняється. Я запитую, чому включити .h, оголосити в ньому прототипи функцій і написати функції в cpp, якщо я можу безпосередньо записати їх в cpp без декларацій?
додано Автор Sam379, джерело
Я не маю на увазі, чому відокремити код. Я запитую, чому мені потрібно оголосити прототипи функцій в .h і написати функції в .cpp, якщо я можу написати їх в .cpp і включити в головний. наприклад я хочу написати клас в окремому файлі (не в main.cpp). Я можу оголосити клас в .h, використовуючи #ifndef #define .. і написати сам клас в cpp і, нарешті, включити myclass.h в main.cpp. Але також я можу зробити myclass.cpp і написати клас в ньому без оголошень .h і включити його в main.cpp. Тому моє запитання: яка різниця між цими двома методами
додано Автор Sam379, джерело
Так, і ви могли б написати це ALL в main.cpp - тому що це по суті те, що включає в себе файл .cpp. Якщо у вас є 378000 рядків коду, ви можете мати трохи менш складний код. Звичайно, при налагодженні, з'ясувати, який вихідний файл дивитися просто. Але дізнатися, яка лінія не буде так весело. Розбиваючи речі, ми можемо ізолювати компоненти один від одного, і, компілюючи один файл .cpp одночасно, ми знаємо, що наша ізоляція працює. Якщо ви просто включите всі ваші .cpp-файли в main.cpp, ви можете, навіть якщо це не призначено, використовувати речі, які ви не повинні.
додано Автор Mats Petersson, джерело
Я подумав, що це те, що я намагався пояснити: Якщо ви відокремили файли .cpp [компілюючи по одному], ми знаємо, що A.cpp використовує щось з B.cpp, оскільки компілятор повідомляє нам, коли це відбудеться. Якщо ви пишете все в одному великому файлі, дуже важко сказати, що саме, по-перше, і по-друге, можливо (вам не потрібно, але ви можете) використовувати речі в A.cpp з B.cpp без "говорити" в Ах або Бх, що вони належать разом.
додано Автор Mats Petersson, джерело

Маючи чітке, логічне розмежування між різними "одиницями" вашої програми, це допомагає тримати її акуратною та акуратною. Це допомагає зрозуміти, куди йде, що використовує, і взагалі "як все це збігається". Якщо ви просто включите все в одну велику крапку коду, дуже легко "не правильно розділяти речі", тому раптом змінна в A.cpp використовується в B.cpp, а не оголошується змінною як "extern" в Ah, або ще краще, має функцію доступу до неї з будь-якого місця, але фактична змінна "захищена" всередині B.cpp, так що ніхто інший не може його використовувати.

Техніка "утримання речей окремо" називається інкапсуляцією - ви бачите тільки "біти" файлу, який насправді піддається заголовку. Таким чином, я, як другий програміст у вашому проекті, знаю, які біти я можу змінити (якщо він працює так само) всередині A.cpp - все, що не в A.h, буде "справедливою грою". Те, що знаходиться в A.h, треба більш ретельно розглядати, оскільки це означає, що щось за межами A.cpp може використовувати його, і ми повинні дивитися, де/як це використовується, перш ніж він може бути змінений.

Це робить велику різницю у великих проектах. Якщо у вас є 100 або 200 рядків коду, ви можете буквально запам'ятати всі рядки коду, і якщо ви щось зміните на рядку 150-160, ви легко зможете пам'ятати, що одна і та ж змінна використовується також у рядках 172 і 189, тому ви потрібно змінити і там. Коли ваш проект довжиною 2000 рядків, одна людина може керуватися знанням більшості всього відразу. Якщо ви написали всі 100k рядків, ви, ймовірно, можете керувати ним. Якщо у вас є 1M рядки коду, більшість з яких хтось написав, вам потрібна хороша структура, щоб мати можливість змінювати речі, не закінчуючи безладом, який не працює. Звичайно, ви ніколи не будете працювати над проектом лінії 5K, якщо ви не покажете, що ви розумієте, як це має бути зроблено в першу чергу.

На жаль, це трохи довго, але загальна ідея полягає в наступному: якщо ви тримаєте його чистим і акуратним, у вас є кращий спосіб роботи, який в кінцевому підсумку приведе до кращого програмного забезпечення.

2
додано
Я не маю на увазі, чому відокремити код. Я запитую, чому мені потрібно оголосити прототипи функцій в .h і написати функції в .cpp, якщо я можу написати їх в .cpp і включити в головний. наприклад я хочу написати клас в окремому файлі (не в main.cpp). Я можу оголосити клас в .h, використовуючи #ifndef #define .. і написати сам клас в cpp і, нарешті, включити myclass.h в main.cpp. Але також я можу зробити myclass.cpp і написати клас в ньому без оголошень .h і включити його в main.cpp. Тому моє запитання: яка різниця між цими двома методами
додано Автор Sam379, джерело
Добре ... але моє питання трохи відрізняється. Я запитую, чому включити .h, оголосити в ньому прототипи функцій і написати функції в cpp, якщо я можу безпосередньо записати їх в cpp без декларацій?
додано Автор Sam379, джерело
Так, і ви могли б написати це ALL в main.cpp - тому що це по суті те, що включає в себе файл .cpp. Якщо у вас є 378000 рядків коду, ви можете мати трохи менш складний код. Звичайно, при налагодженні, з'ясувати, який вихідний файл дивитися просто. Але дізнатися, яка лінія не буде так весело. Розбиваючи речі, ми можемо ізолювати компоненти один від одного, і, компілюючи один файл .cpp одночасно, ми знаємо, що наша ізоляція працює. Якщо ви просто включите всі ваші .cpp-файли в main.cpp, ви можете, навіть якщо це не призначено, використовувати речі, які ви не повинні.
додано Автор Mats Petersson, джерело
Я подумав, що це те, що я намагався пояснити: Якщо ви відокремили файли .cpp [компілюючи по одному], ми знаємо, що A.cpp використовує щось з B.cpp, оскільки компілятор повідомляє нам, коли це відбудеться. Якщо ви пишете все в одному великому файлі, дуже важко сказати, що саме, по-перше, і по-друге, можливо (вам не потрібно, але ви можете) використовувати речі в A.cpp з B.cpp без "говорити" в Ах або Бх, що вони належать разом.
додано Автор Mats Petersson, джерело

Маючи чітке, логічне розмежування між різними "одиницями" вашої програми, це допомагає тримати її акуратною та акуратною. Це допомагає зрозуміти, куди йде, що використовує, і взагалі "як все це збігається". Якщо ви просто включите все в одну велику крапку коду, дуже легко "не правильно розділяти речі", тому раптом змінна в A.cpp використовується в B.cpp, а не оголошується змінною як "extern" в Ah, або ще краще, має функцію доступу до неї з будь-якого місця, але фактична змінна "захищена" всередині B.cpp, так що ніхто інший не може його використовувати.

Техніка "утримання речей окремо" називається інкапсуляцією - ви бачите тільки "біти" файлу, який насправді піддається заголовку. Таким чином, я, як другий програміст у вашому проекті, знаю, які біти я можу змінити (якщо він працює так само) всередині A.cpp - все, що не в A.h, буде "справедливою грою". Те, що знаходиться в A.h, треба більш ретельно розглядати, оскільки це означає, що щось за межами A.cpp може використовувати його, і ми повинні дивитися, де/як це використовується, перш ніж він може бути змінений.

Це робить велику різницю у великих проектах. Якщо у вас є 100 або 200 рядків коду, ви можете буквально запам'ятати всі рядки коду, і якщо ви щось зміните на рядку 150-160, ви легко зможете пам'ятати, що одна і та ж змінна використовується також у рядках 172 і 189, тому ви потрібно змінити і там. Коли ваш проект довжиною 2000 рядків, одна людина може керуватися знанням більшості всього відразу. Якщо ви написали всі 100k рядків, ви, ймовірно, можете керувати ним. Якщо у вас є 1M рядки коду, більшість з яких хтось написав, вам потрібна хороша структура, щоб мати можливість змінювати речі, не закінчуючи безладом, який не працює. Звичайно, ви ніколи не будете працювати над проектом лінії 5K, якщо ви не покажете, що ви розумієте, як це має бути зроблено в першу чергу.

На жаль, це трохи довго, але загальна ідея полягає в наступному: якщо ви тримаєте його чистим і акуратним, у вас є кращий спосіб роботи, який в кінцевому підсумку приведе до кращого програмного забезпечення.

2
додано
Добре ... але моє питання трохи відрізняється. Я запитую, чому включити .h, оголосити в ньому прототипи функцій і написати функції в cpp, якщо я можу безпосередньо записати їх в cpp без декларацій?
додано Автор Sam379, джерело
Я не маю на увазі, чому відокремити код. Я запитую, чому мені потрібно оголосити прототипи функцій в .h і написати функції в .cpp, якщо я можу написати їх в .cpp і включити в головний. наприклад я хочу написати клас в окремому файлі (не в main.cpp). Я можу оголосити клас в .h, використовуючи #ifndef #define .. і написати сам клас в cpp і, нарешті, включити myclass.h в main.cpp. Але також я можу зробити myclass.cpp і написати клас в ньому без оголошень .h і включити його в main.cpp. Тому моє запитання: яка різниця між цими двома методами
додано Автор Sam379, джерело
Так, і ви могли б написати це ALL в main.cpp - тому що це по суті те, що включає в себе файл .cpp. Якщо у вас є 378000 рядків коду, ви можете мати трохи менш складний код. Звичайно, при налагодженні, з'ясувати, який вихідний файл дивитися просто. Але дізнатися, яка лінія не буде так весело. Розбиваючи речі, ми можемо ізолювати компоненти один від одного, і, компілюючи один файл .cpp одночасно, ми знаємо, що наша ізоляція працює. Якщо ви просто включите всі ваші .cpp-файли в main.cpp, ви можете, навіть якщо це не призначено, використовувати речі, які ви не повинні.
додано Автор Mats Petersson, джерело
Я подумав, що це те, що я намагався пояснити: Якщо ви відокремили файли .cpp [компілюючи по одному], ми знаємо, що A.cpp використовує щось з B.cpp, оскільки компілятор повідомляє нам, коли це відбудеться. Якщо ви пишете все в одному великому файлі, дуже важко сказати, що саме, по-перше, і по-друге, можливо (вам не потрібно, але ви можете) використовувати речі в A.cpp з B.cpp без "говорити" в Ах або Бх, що вони належать разом.
додано Автор Mats Petersson, джерело

Маючи чітке, логічне розмежування між різними "одиницями" вашої програми, це допомагає тримати її акуратною та акуратною. Це допомагає зрозуміти, куди йде, що використовує, і взагалі "як все це збігається". Якщо ви просто включите все в одну велику крапку коду, дуже легко "не правильно розділяти речі", тому раптом змінна в A.cpp використовується в B.cpp, а не оголошується змінною як "extern" в Ah, або ще краще, має функцію доступу до неї з будь-якого місця, але фактична змінна "захищена" всередині B.cpp, так що ніхто інший не може його використовувати.

Техніка "утримання речей окремо" називається інкапсуляцією - ви бачите тільки "біти" файлу, який насправді піддається заголовку. Таким чином, я, як другий програміст у вашому проекті, знаю, які біти я можу змінити (якщо він працює так само) всередині A.cpp - все, що не в A.h, буде "справедливою грою". Те, що знаходиться в A.h, треба більш ретельно розглядати, оскільки це означає, що щось за межами A.cpp може використовувати його, і ми повинні дивитися, де/як це використовується, перш ніж він може бути змінений.

Це робить велику різницю у великих проектах. Якщо у вас є 100 або 200 рядків коду, ви можете буквально запам'ятати всі рядки коду, і якщо ви щось зміните на рядку 150-160, ви легко зможете пам'ятати, що одна і та ж змінна використовується також у рядках 172 і 189, тому ви потрібно змінити і там. Коли ваш проект довжиною 2000 рядків, одна людина може керуватися знанням більшості всього відразу. Якщо ви написали всі 100k рядків, ви, ймовірно, можете керувати ним. Якщо у вас є 1M рядки коду, більшість з яких хтось написав, вам потрібна хороша структура, щоб мати можливість змінювати речі, не закінчуючи безладом, який не працює. Звичайно, ви ніколи не будете працювати над проектом лінії 5K, якщо ви не покажете, що ви розумієте, як це має бути зроблено в першу чергу.

На жаль, це трохи довго, але загальна ідея полягає в наступному: якщо ви тримаєте його чистим і акуратним, у вас є кращий спосіб роботи, який в кінцевому підсумку приведе до кращого програмного забезпечення.

2
додано
Добре ... але моє питання трохи відрізняється. Я запитую, чому включити .h, оголосити в ньому прототипи функцій і написати функції в cpp, якщо я можу безпосередньо записати їх в cpp без декларацій?
додано Автор Sam379, джерело
Я не маю на увазі, чому відокремити код. Я запитую, чому мені потрібно оголосити прототипи функцій в .h і написати функції в .cpp, якщо я можу написати їх в .cpp і включити в головний. наприклад я хочу написати клас в окремому файлі (не в main.cpp). Я можу оголосити клас в .h, використовуючи #ifndef #define .. і написати сам клас в cpp і, нарешті, включити myclass.h в main.cpp. Але також я можу зробити myclass.cpp і написати клас в ньому без оголошень .h і включити його в main.cpp. Тому моє запитання: яка різниця між цими двома методами
додано Автор Sam379, джерело
Так, і ви могли б написати це ALL в main.cpp - тому що це по суті те, що включає в себе файл .cpp. Якщо у вас є 378000 рядків коду, ви можете мати трохи менш складний код. Звичайно, при налагодженні, з'ясувати, який вихідний файл дивитися просто. Але дізнатися, яка лінія не буде так весело. Розбиваючи речі, ми можемо ізолювати компоненти один від одного, і, компілюючи один файл .cpp одночасно, ми знаємо, що наша ізоляція працює. Якщо ви просто включите всі ваші .cpp-файли в main.cpp, ви можете, навіть якщо це не призначено, використовувати речі, які ви не повинні.
додано Автор Mats Petersson, джерело
Я подумав, що це те, що я намагався пояснити: Якщо ви відокремили файли .cpp [компілюючи по одному], ми знаємо, що A.cpp використовує щось з B.cpp, оскільки компілятор повідомляє нам, коли це відбудеться. Якщо ви пишете все в одному великому файлі, дуже важко сказати, що саме, по-перше, і по-друге, можливо (вам не потрібно, але ви можете) використовувати речі в A.cpp з B.cpp без "говорити" в Ах або Бх, що вони належать разом.
додано Автор Mats Petersson, джерело

Це потенційно призводить до двох досить різних типів проблем.

По-перше, це може призвести до тривалого часу будівництва. Коли ви зберігаєте файли .cpp окремо, ви можете скомпілювати цей файл, коли ви його змінюєте, але в іншому випадку просто посилаєтеся на посилання на функції в цьому файлі без повторного компіляції кожного разу. Поки ваші проекти невеликі, повторна компіляція кожного коду не є головною проблемою, але якщо проект стає дуже великим, він може швидко стати серйозною турботою.

Другою проблемою є множинні визначення однієї і тієї ж функції. Припустимо, наприклад, ви визначили деякі функції в A.cpp, і ви повинні використовувати ці функції як у B.cpp, так і в C.cpp. Якщо ви безпосередньо включите вихідні коди цих функцій (а не тільки декларації) у B.cpp і C.cpp, а потім спробуйте зв'язати B і C разом, у вас є кілька визначень всіх функцій в A.cpp. Результат у невизначеному поведінці. У більшості випадків лінкер скаже вам, що функції були визначені більше одного разу, але ви не можете повністю залежати від цього.

2
додано

Це потенційно призводить до двох досить різних типів проблем.

По-перше, це може призвести до тривалого часу будівництва. Коли ви зберігаєте файли .cpp окремо, ви можете скомпілювати цей файл, коли ви його змінюєте, але в іншому випадку просто посилаєтеся на посилання на функції в цьому файлі без повторного компіляції кожного разу. Поки ваші проекти невеликі, повторна компіляція кожного коду не є головною проблемою, але якщо проект стає дуже великим, він може швидко стати серйозною турботою.

Другою проблемою є множинні визначення однієї і тієї ж функції. Припустимо, наприклад, ви визначили деякі функції в A.cpp, і ви повинні використовувати ці функції як у B.cpp, так і в C.cpp. Якщо ви безпосередньо включите вихідні коди цих функцій (а не тільки декларації) у B.cpp і C.cpp, а потім спробуйте зв'язати B і C разом, у вас є кілька визначень всіх функцій в A.cpp. Результат у невизначеному поведінці. У більшості випадків лінкер скаже вам, що функції були визначені більше одного разу, але ви не можете повністю залежати від цього.

2
додано

Це потенційно призводить до двох досить різних типів проблем.

По-перше, це може призвести до тривалого часу будівництва. Коли ви зберігаєте файли .cpp окремо, ви можете скомпілювати цей файл, коли ви його змінюєте, але в іншому випадку просто посилаєтеся на посилання на функції в цьому файлі без повторного компіляції кожного разу. Поки ваші проекти невеликі, повторна компіляція кожного коду не є головною проблемою, але якщо проект стає дуже великим, він може швидко стати серйозною турботою.

Другою проблемою є множинні визначення однієї і тієї ж функції. Припустимо, наприклад, ви визначили деякі функції в A.cpp, і ви повинні використовувати ці функції як у B.cpp, так і в C.cpp. Якщо ви безпосередньо включите вихідні коди цих функцій (а не тільки декларації) у B.cpp і C.cpp, а потім спробуйте зв'язати B і C разом, у вас є кілька визначень всіх функцій в A.cpp. Результат у невизначеному поведінці. У більшості випадків лінкер скаже вам, що функції були визначені більше одного разу, але ви не можете повністю залежати від цього.

2
додано
  • Розділення коду на файли надає корисну логічну групування, щоб допомогти програмі.
  • Розщеплення в багатьох випадках призведе до більш швидкої компіляції.
  • Розщеплення дозволить вам робити речі з круговими залежностями (хоча їх можна уникати, коли це можливо).
  • Деякі компілятори не зможуть обробляти великі проекти, які зібрані в один main.cpp .
2
додано
  • Розділення коду на файли надає корисну логічну групування, щоб допомогти програмі.
  • Розщеплення в багатьох випадках призведе до більш швидкої компіляції.
  • Розщеплення дозволить вам робити речі з круговими залежностями (хоча їх можна уникати, коли це можливо).
  • Деякі компілятори не зможуть обробляти великі проекти, які зібрані в один main.cpp .
2
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147