О, это сложно объяснить. Но кратко - Си в изначальном варианте не поддерживал условную компиляцию. Ты не мог написать один файл, который компилировался на любой поддерживаемой платформе одинаково. Пришлось бы держать отдельную копию исходного файла под каждую целевую платформу. Поэтому возникла идея языка шаблонов или точнее - метапрограммирования, что реализуется препроцессором Си. Он берет исходный файл и по определённым правилам согласно своих директив превращает его в то, что пойдет на вход компилятору. И директива `#include` позволила подключать библиотеки кодов. А потом препроцессор исторически перекочевал в С++ из необходимости обеспечения совместимости.
Сейчас в современном С++ иногда приходится прибегать к этой магии макросов, например, при написании переносимого кода, если не хватает штатного функционала языка - шаблонов, рефлексии и пр. Но при прочих равных активное использование макросов считается не очень хорошим тоном, т.к. вменяемых средств их отладки нет и сообщения об ошибках могут быть весьма запутанными.