Эта тема тесно связана с 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++.