diff --git a/README.md b/README.md index 870103f..4c504a1 100644 --- a/README.md +++ b/README.md @@ -68,10 +68,11 @@ 7. [Разыменование nullptr](runtime/nullptr_dereference.md) 8. [Static initialization order fiasco](runtime/static_initialization_order_fiasco.md) 9. [ODR violation](runtime/odr_violation.md) - 10. [Тривиальные типы и ABI](runtime/trivial_types_and_ABI.md) - 11. [Неинициализированные переменные](runtime/uninitialized.md) - 12. [Ranges. Unreachable sentinel](runtime/unreachable_sentinel.md) - 13. [Невиртуальные виртуальные функции](runtime/virtual_functions.md) + 10. [Зарезервированные имена](runtime/reserved_names.md) + 11. [Тривиальные типы и ABI](runtime/trivial_types_and_ABI.md) + 12. [Неинициализированные переменные](runtime/uninitialized.md) + 13. [Ranges. Unreachable sentinel](runtime/unreachable_sentinel.md) + 14. [Невиртуальные виртуальные функции](runtime/virtual_functions.md) 7. Происхождение указателей 1. [Невалидные указатели](pointer_prominence/invalid_pointer.md) 2. [Placement `operator new[]`](pointer_prominence/array_placement_new.md) diff --git a/runtime/reserved_names.md b/runtime/reserved_names.md new file mode 100644 index 0000000..2e0c0c9 --- /dev/null +++ b/runtime/reserved_names.md @@ -0,0 +1,55 @@ +# Зарезервированные имена + +Эта тема тесно связана с [ODR violation](odr_violation.md). + +В C/C++ невероятно много идентификаторов, использовать которые для своих переменных и типов запрещено под страхом неопределенного поведения. + +Некоторые имена запрещены самим стандартом C/C++. Некоторые — стандартами POSIX. + +Так в глобальной области видимости нельзя использовать имена функций из библиотеки C. Ни в C, ни в C++! +Иначе вы можете столкнуться не только с ODR-violation, но еще и с удивительным поведением компиляторов, умеющих отпимизировать распространненные конструкции. + +Так, если определить свой собственный `memset`: + +```C +void *memset (void *destination, int c, unsigned long n) { + for (unsigned long i = 0; i < n; ++i) { + ((char*)(destination))[i] = c; + } + return destination; +} +``` +Заботливый оптимизирующий компилятор может запросто [превратить](https://godbolt.org/z/fKfeqza6a) его в +```C +void *memset (void* destination, int c, unsigned long n) { + return memset(destination, c, n); +} +``` + +В C++, благодаря включенному по умолчанию декорированию имен, рекурсии не будет — вызовется стандартный `memset`, вместо нашего. + +Однако, декорирование не спасает, если объявлять не функции, а глобальные переменные. + +```C++ +#include +int read; +int main(){ + std::ios_base::sync_with_stdio(false); + std::cin >> read; +} +``` +При сборке такого примера со статически влинкованной стандартной библиотекой C, программа [упадет](https://godbolt.org/z/sq9bqhn46). +Так как вместо адреса стандартной функции `read` будет подставлен адрес глобальной переменной `read`. Аналогичный пример с использованием имени `write` предлагается читателю воплотить самостоятельно в качестве упражнения. + +Запретных имен много. Например, все, что начинается с `is*`, `to*` или `_*` запрещено в глобальном простанстве. `_[A-Z]*` запрещены вообще везде. POSIX резервирует имена, заканчивающиеся на `_t`. И еще много всего неожиданного. +С более полными списками можно ознакомиться по ссылкам. + +Если вы пользуетесь запрещенными именами, то сегодня может всё работать, но не завтра. + +Чтобы не жить в страхе во многих случаях достаточно использовать `static` или анонимные пространства имен. Или просто не использовать C/C++. + + +## Полезные ссылки +1. https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html +2. https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier +3. https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL51-CPP.+Do+not+declare+or+define+a+reserved+identifier \ No newline at end of file