Skip to content

Latest commit

 

History

History
55 lines (41 loc) · 4.02 KB

reserved_names.md

File metadata and controls

55 lines (41 loc) · 4.02 KB

Зарезервированные имена

Эта тема тесно связана с ODR violation.

В C/C++ невероятно много идентификаторов, использовать которые для своих переменных и типов запрещено под страхом неопределенного поведения.

Некоторые имена запрещены самим стандартом C/C++. Некоторые — стандартами POSIX. Некоторые — платформоспецифическими библиотеками. В последнем случая обычно вам ничего не грозит, пока библиотека не подключена.

Так в глобальной области видимости нельзя использовать имена функций из библиотеки C. Ни в C, ни в C++! Иначе вы можете столкнуться не только с ODR-violation, но еще и с удивительным поведением компиляторов, умеющих оптимизировать распространенные конструкции.

Так, если определить свой собственный memset:

void *memset (void *destination, int c, unsigned long n) {
    for (unsigned long i = 0; i < n; ++i) {
        ((char*)(destination))[i] = c;
    }
    return destination;
}

Заботливый оптимизирующий компилятор может запросто превратить его в

void *memset (void* destination, int c, unsigned long n) {
    return memset(destination, c, n);
}

В C++, благодаря включенному по умолчанию декорированию имен, рекурсии не будет — вызовется стандартный memset, вместо нашего.

Однако, декорирование не спасает, если объявлять не функции, а глобальные переменные.

#include <iostream>
int read;
int main(){
    std::ios_base::sync_with_stdio(false);
    std::cin >> read;
}

При сборке такого примера со статически влинкованной стандартной библиотекой C, программа упадет. Так как вместо адреса стандартной функции 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